propline-mcp 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -105,6 +105,11 @@ var PropLineClient = class {
105
105
  daysFrom: opts.daysFrom
106
106
  });
107
107
  }
108
+ getMlbGrandSalami(opts = {}) {
109
+ return this.request(`/v1/sports/baseball_mlb/grand-salami`, {
110
+ date: opts.date
111
+ });
112
+ }
108
113
  getResolutionSummary(opts = {}) {
109
114
  return this.request(`/v1/markets/resolution-summary`, {
110
115
  days: opts.days
@@ -133,16 +138,21 @@ var PropLineClient = class {
133
138
  };
134
139
 
135
140
  // src/index.ts
136
- var VERSION = "0.2.2";
141
+ var VERSION = "0.3.0";
137
142
  var apiKey = process.env.PROPLINE_API_KEY;
138
143
  var baseUrl = process.env.PROPLINE_BASE_URL;
139
- if (!apiKey) {
140
- console.error(
141
- "[propline-mcp] PROPLINE_API_KEY not set. Get a free key at https://prop-line.com and set it in your MCP client config."
142
- );
143
- process.exit(1);
144
+ var _client = null;
145
+ function client() {
146
+ if (!_client) {
147
+ if (!apiKey) {
148
+ throw new Error(
149
+ "PROPLINE_API_KEY is not set. Get a free key at https://prop-line.com and add it to your MCP client config (env var: PROPLINE_API_KEY)."
150
+ );
151
+ }
152
+ _client = new PropLineClient({ apiKey, baseUrl });
153
+ }
154
+ return _client;
144
155
  }
145
- var client = new PropLineClient({ apiKey, baseUrl });
146
156
  var tools = [
147
157
  {
148
158
  name: "propline_list_sports",
@@ -152,7 +162,7 @@ var tools = [
152
162
  properties: {},
153
163
  additionalProperties: false
154
164
  },
155
- handler: () => client.listSports()
165
+ handler: () => client().listSports()
156
166
  },
157
167
  {
158
168
  name: "propline_list_events",
@@ -172,7 +182,7 @@ var tools = [
172
182
  required: ["sport_key"],
173
183
  additionalProperties: false
174
184
  },
175
- handler: (args) => client.listEvents(args.sport_key, {
185
+ handler: (args) => client().listEvents(args.sport_key, {
176
186
  live: args.live
177
187
  })
178
188
  },
@@ -188,7 +198,7 @@ var tools = [
188
198
  required: ["sport_key", "event_id"],
189
199
  additionalProperties: false
190
200
  },
191
- handler: (args) => client.listEventMarkets(
201
+ handler: (args) => client().listEventMarkets(
192
202
  args.sport_key,
193
203
  args.event_id
194
204
  )
@@ -216,7 +226,7 @@ var tools = [
216
226
  required: ["sport_key"],
217
227
  additionalProperties: false
218
228
  },
219
- handler: (args) => client.getOdds(args.sport_key, {
229
+ handler: (args) => client().getOdds(args.sport_key, {
220
230
  eventId: args.event_id,
221
231
  markets: args.markets,
222
232
  bookmakers: args.bookmakers
@@ -235,7 +245,7 @@ var tools = [
235
245
  required: ["sport_key", "event_id"],
236
246
  additionalProperties: false
237
247
  },
238
- handler: (args) => client.getOddsHistory(
248
+ handler: (args) => client().getOddsHistory(
239
249
  args.sport_key,
240
250
  args.event_id,
241
251
  { markets: args.markets }
@@ -256,10 +266,28 @@ var tools = [
256
266
  required: ["sport_key"],
257
267
  additionalProperties: false
258
268
  },
259
- handler: (args) => client.getScores(args.sport_key, {
269
+ handler: (args) => client().getScores(args.sport_key, {
260
270
  daysFrom: args.days_from
261
271
  })
262
272
  },
273
+ {
274
+ name: "propline_get_mlb_grand_salami",
275
+ description: "Free-tier endpoint. Returns the synthetic daily MLB Grand Salami for a given UTC date \u2014 total runs scored across every MLB game on the slate plus each book's implied Grand Salami line (median of per-game primary totals across our MLB books incl. Pinnacle, Polymarket, Matchbook, Smarkets). No retail sportsbook quotes this as a single market. Useful for: 'what's the total run line for tonight's full MLB slate', 'did the Grand Salami go over yesterday', 'historical Grand Salami results for backtesting'.",
276
+ inputSchema: {
277
+ type: "object",
278
+ properties: {
279
+ date: {
280
+ type: "string",
281
+ description: "YYYY-MM-DD UTC date. Defaults to today (UTC) when omitted."
282
+ }
283
+ },
284
+ required: [],
285
+ additionalProperties: false
286
+ },
287
+ handler: (args) => client().getMlbGrandSalami({
288
+ date: args.date
289
+ })
290
+ },
263
291
  {
264
292
  name: "propline_get_resolution_summary",
265
293
  description: "Free-tier endpoint. Returns the factual volume of player props PropLine has graded against real box scores over the last N days (aggregated counts only): total graded/settled, games, sports covered, plus per-sport and top-market breakdowns. Useful for: 'how much graded prop data does PropLine have, what's the coverage'. A coverage proof, never a profitability claim.",
@@ -274,7 +302,7 @@ var tools = [
274
302
  required: [],
275
303
  additionalProperties: false
276
304
  },
277
- handler: (args) => client.getResolutionSummary({ days: args.days })
305
+ handler: (args) => client().getResolutionSummary({ days: args.days })
278
306
  },
279
307
  {
280
308
  name: "propline_get_event_stats",
@@ -288,7 +316,7 @@ var tools = [
288
316
  required: ["sport_key", "event_id"],
289
317
  additionalProperties: false
290
318
  },
291
- handler: (args) => client.getEventStats(
319
+ handler: (args) => client().getEventStats(
292
320
  args.sport_key,
293
321
  args.event_id
294
322
  )
@@ -305,7 +333,7 @@ var tools = [
305
333
  required: ["sport_key", "event_id"],
306
334
  additionalProperties: false
307
335
  },
308
- handler: (args) => client.getEventResults(
336
+ handler: (args) => client().getEventResults(
309
337
  args.sport_key,
310
338
  args.event_id
311
339
  )
@@ -333,7 +361,7 @@ var tools = [
333
361
  required: ["sport_key", "player_name"],
334
362
  additionalProperties: false
335
363
  },
336
- handler: (args) => client.getPlayerHistory(
364
+ handler: (args) => client().getPlayerHistory(
337
365
  args.sport_key,
338
366
  args.player_name,
339
367
  {
@@ -359,7 +387,7 @@ var tools = [
359
387
  required: ["sport_key", "event_id"],
360
388
  additionalProperties: false
361
389
  },
362
- handler: (args) => client.getEventEv(
390
+ handler: (args) => client().getEventEv(
363
391
  args.sport_key,
364
392
  args.event_id,
365
393
  {
@@ -410,6 +438,11 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
410
438
  var transport = new StdioServerTransport();
411
439
  await server.connect(transport);
412
440
  console.error(`[propline-mcp ${VERSION}] connected via stdio`);
441
+ if (!apiKey) {
442
+ console.error(
443
+ "[propline-mcp] note: PROPLINE_API_KEY is not set. Tools are listed for discovery, but any tool call will error until you configure it. Free key: https://prop-line.com"
444
+ );
445
+ }
413
446
  export {
414
447
  VERSION
415
448
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/client.ts"],"sourcesContent":["/**\n * PropLine MCP server.\n *\n * Exposes the PropLine REST API as Model Context Protocol tools so AI\n * clients (Claude Desktop, Claude Code, ChatGPT desktop with MCP, etc.)\n * can pull live odds, prop resolution, cross-book +EV, scores, and\n * box-score stats directly via tool calls.\n *\n * Run via: npx -y propline-mcp\n * Auth: PROPLINE_API_KEY env var (free key at https://prop-line.com)\n * Optional: PROPLINE_BASE_URL env var (override for self-hosted setups)\n */\n\nimport { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n} from \"@modelcontextprotocol/sdk/types.js\";\n\nimport { PropLineClient, PropLineHTTPError } from \"./client.js\";\n\nexport const VERSION = \"0.2.2\";\n\nconst apiKey = process.env.PROPLINE_API_KEY;\nconst baseUrl = process.env.PROPLINE_BASE_URL;\n\nif (!apiKey) {\n console.error(\n \"[propline-mcp] PROPLINE_API_KEY not set. Get a free key at \" +\n \"https://prop-line.com and set it in your MCP client config.\",\n );\n process.exit(1);\n}\n\nconst client = new PropLineClient({ apiKey, baseUrl });\n\n// ---------------------------------------------------------------------\n// Tool definitions\n// ---------------------------------------------------------------------\n\ninterface ToolDef {\n name: string;\n description: string;\n inputSchema: {\n type: \"object\";\n properties: Record<string, unknown>;\n required?: string[];\n additionalProperties?: boolean;\n };\n // Returns either JSON-serializable data (will be JSON.stringify'd in the\n // tool result) or a string (returned as-is).\n handler: (args: Record<string, unknown>) => Promise<unknown>;\n}\n\nconst tools: ToolDef[] = [\n {\n name: \"propline_list_sports\",\n description:\n \"List all sports PropLine currently polls. Returns sport keys \" +\n \"(e.g. baseball_mlb, basketball_nba, soccer_epl) along with human \" +\n \"titles and active status. Use this first to discover what \" +\n \"sport_key values are valid for the other tools.\",\n inputSchema: {\n type: \"object\",\n properties: {},\n additionalProperties: false,\n },\n handler: () => client.listSports(),\n },\n {\n name: \"propline_list_events\",\n description:\n \"List upcoming events for a sport. Returns each event's id, \" +\n \"home_team, away_team, commence_time. Use the returned event_id \" +\n \"to drill into per-event odds, props, +EV, or results.\",\n inputSchema: {\n type: \"object\",\n properties: {\n sport_key: {\n type: \"string\",\n description:\n \"Sport key from propline_list_sports — e.g. baseball_mlb, basketball_nba\",\n },\n live: {\n type: \"boolean\",\n description:\n \"If true, only return in-progress (live) events. Defaults to false.\",\n },\n },\n required: [\"sport_key\"],\n additionalProperties: false,\n },\n handler: (args) =>\n client.listEvents(args.sport_key as string, {\n live: args.live as boolean | undefined,\n }),\n },\n {\n name: \"propline_list_event_markets\",\n description:\n \"List the market types available for a specific event (e.g. h2h, \" +\n \"spreads, totals, player_points, pitcher_strikeouts). Useful when \" +\n \"you don't know which prop markets a given event carries.\",\n inputSchema: {\n type: \"object\",\n properties: {\n sport_key: { type: \"string\" },\n event_id: { type: [\"string\", \"number\"] },\n },\n required: [\"sport_key\", \"event_id\"],\n additionalProperties: false,\n },\n handler: (args) =>\n client.listEventMarkets(\n args.sport_key as string,\n args.event_id as string | number,\n ),\n },\n {\n name: \"propline_get_odds\",\n description:\n \"Get live odds. If event_id is supplied, returns full per-event \" +\n \"props for that event; otherwise returns bulk game-line odds for \" +\n \"the whole sport. Pass markets as a comma-separated list (e.g. \" +\n \"'h2h,spreads,totals' or 'player_points,player_rebounds'). \" +\n \"Response includes a bookmakers[] array across every book that \" +\n \"carries the requested markets (currently up to 13: Bovada, \" +\n \"DraftKings, FanDuel, Pinnacle, BetMGM, BetRivers, Unibet, \" +\n \"Underdog, PrizePicks, Kalshi, Polymarket, Matchbook, Smarkets \" +\n \"— coverage varies by sport).\",\n inputSchema: {\n type: \"object\",\n properties: {\n sport_key: { type: \"string\" },\n event_id: {\n type: [\"string\", \"number\"],\n description: \"Optional. If set, returns props for this event.\",\n },\n markets: {\n type: \"string\",\n description:\n \"Comma-separated market keys. Defaults to h2h on bulk; h2h,spreads,totals on event. Pass an explicit list to fetch player props (sport-specific — e.g. player_points,player_rebounds for NBA; pitcher_strikeouts,batter_home_runs for MLB).\",\n },\n bookmakers: {\n type: \"string\",\n description:\n \"Comma-separated subset of book keys (bovada, draftkings, fanduel, pinnacle, betmgm, betrivers, unibet, underdog, prizepicks, kalshi, polymarket, matchbook, smarkets). Default returns all available.\",\n },\n },\n required: [\"sport_key\"],\n additionalProperties: false,\n },\n handler: (args) =>\n client.getOdds(args.sport_key as string, {\n eventId: args.event_id as string | number | undefined,\n markets: args.markets as string | undefined,\n bookmakers: args.bookmakers as string | undefined,\n }),\n },\n {\n name: \"propline_get_odds_history\",\n description:\n \"Pro-tier endpoint. Returns the historical line-movement snapshot \" +\n \"series for an event (every recorded price/point change per \" +\n \"outcome over the event's lifetime). Free tier returns market \" +\n \"structure with redacted snapshots and an upgrade pointer.\",\n inputSchema: {\n type: \"object\",\n properties: {\n sport_key: { type: \"string\" },\n event_id: { type: [\"string\", \"number\"] },\n markets: { type: \"string\" },\n },\n required: [\"sport_key\", \"event_id\"],\n additionalProperties: false,\n },\n handler: (args) =>\n client.getOddsHistory(\n args.sport_key as string,\n args.event_id as string | number,\n { markets: args.markets as string | undefined },\n ),\n },\n {\n name: \"propline_get_scores\",\n description:\n \"Free-tier endpoint. Returns recent and live game scores plus \" +\n \"status (scheduled, live, final) for a sport. Useful for: 'is \" +\n \"this game over yet, what was the final score'.\",\n inputSchema: {\n type: \"object\",\n properties: {\n sport_key: { type: \"string\" },\n days_from: {\n type: \"number\",\n description:\n \"How many past days of completed games to include. Defaults to 1.\",\n },\n },\n required: [\"sport_key\"],\n additionalProperties: false,\n },\n handler: (args) =>\n client.getScores(args.sport_key as string, {\n daysFrom: args.days_from as number | undefined,\n }),\n },\n {\n name: \"propline_get_resolution_summary\",\n description:\n \"Free-tier endpoint. Returns the factual volume of player props \" +\n \"PropLine has graded against real box scores over the last N days \" +\n \"(aggregated counts only): total graded/settled, games, sports \" +\n \"covered, plus per-sport and top-market breakdowns. Useful for: \" +\n \"'how much graded prop data does PropLine have, what's the \" +\n \"coverage'. A coverage proof, never a profitability claim.\",\n inputSchema: {\n type: \"object\",\n properties: {\n days: {\n type: \"number\",\n description: \"Look-back window, 1-90. Defaults to 30.\",\n },\n },\n required: [],\n additionalProperties: false,\n },\n handler: (args) =>\n client.getResolutionSummary({ days: args.days as number | undefined }),\n },\n {\n name: \"propline_get_event_stats\",\n description:\n \"Book-agnostic raw box-score stats for a completed event. Returns \" +\n \"per-player stats (e.g. strikeouts, hits, points, rebounds, \" +\n \"shots-on-goal) decoupled from any sportsbook's lines. Free tier.\",\n inputSchema: {\n type: \"object\",\n properties: {\n sport_key: { type: \"string\" },\n event_id: { type: [\"string\", \"number\"] },\n },\n required: [\"sport_key\", \"event_id\"],\n additionalProperties: false,\n },\n handler: (args) =>\n client.getEventStats(\n args.sport_key as string,\n args.event_id as string | number,\n ),\n },\n {\n name: \"propline_get_event_results\",\n description:\n \"Pro-tier endpoint. Returns graded prop outcomes for a completed \" +\n \"event — every Over/Under marked won, lost, push, or void with \" +\n \"the actual stat value next to the line. The single most \" +\n \"distinctive feature vs the-odds-api: they don't grade props at \" +\n \"any tier. Free tier returns the same structure with resolution \" +\n \"and actual_value redacted plus an upgrade pointer.\",\n inputSchema: {\n type: \"object\",\n properties: {\n sport_key: { type: \"string\" },\n event_id: { type: [\"string\", \"number\"] },\n },\n required: [\"sport_key\", \"event_id\"],\n additionalProperties: false,\n },\n handler: (args) =>\n client.getEventResults(\n args.sport_key as string,\n args.event_id as string | number,\n ),\n },\n {\n name: \"propline_get_player_history\",\n description:\n \"Player prop history across recent games. Returns each prior prop \" +\n \"this player took with line, prices, resolution, and actual value. \" +\n \"Pro tier returns full data; free tier returns redacted \" +\n \"resolution/actual_value with an upgrade pointer.\",\n inputSchema: {\n type: \"object\",\n properties: {\n sport_key: { type: \"string\" },\n player_name: {\n type: \"string\",\n description:\n \"Player name as it appears in box scores — e.g. 'Aaron Judge', 'Nikola Jokic'\",\n },\n limit: {\n type: \"number\",\n description: \"Max number of past games (default 20, max 100)\",\n },\n markets: {\n type: \"string\",\n description:\n \"Comma-separated subset of markets (e.g. 'player_points,player_rebounds')\",\n },\n },\n required: [\"sport_key\", \"player_name\"],\n additionalProperties: false,\n },\n handler: (args) =>\n client.getPlayerHistory(\n args.sport_key as string,\n args.player_name as string,\n {\n limit: args.limit as number | undefined,\n markets: args.markets as string | undefined,\n },\n ),\n },\n {\n name: \"propline_get_event_ev\",\n description:\n \"Pro-tier endpoint. Returns cross-book +EV per outcome for an \" +\n \"event. We anchor on Pinnacle's sharp line, remove vig, derive a \" +\n \"no-vig fair line, and compute EV% per book at the same line. \" +\n \"Outcomes are sorted with +EV plays floated to the top of each \" +\n \"line group. PrizePicks is excluded from EV math (DFS payouts \" +\n \"aren't comparable to per-book prices).\",\n inputSchema: {\n type: \"object\",\n properties: {\n sport_key: { type: \"string\" },\n event_id: { type: [\"string\", \"number\"] },\n markets: { type: \"string\" },\n min_ev_pct: {\n type: \"number\",\n description: \"Filter to outcomes with EV ≥ this percent (e.g. 2.0).\",\n },\n },\n required: [\"sport_key\", \"event_id\"],\n additionalProperties: false,\n },\n handler: (args) =>\n client.getEventEv(\n args.sport_key as string,\n args.event_id as string | number,\n {\n markets: args.markets as string | undefined,\n minEvPct: args.min_ev_pct as number | undefined,\n },\n ),\n },\n];\n\n// ---------------------------------------------------------------------\n// MCP server wiring\n// ---------------------------------------------------------------------\n\nconst server = new Server(\n { name: \"propline-mcp\", version: VERSION },\n { capabilities: { tools: {} } },\n);\n\nserver.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools: tools.map((t) => ({\n name: t.name,\n description: t.description,\n inputSchema: t.inputSchema,\n })),\n}));\n\nserver.setRequestHandler(CallToolRequestSchema, async (req) => {\n const tool = tools.find((t) => t.name === req.params.name);\n if (!tool) {\n return {\n isError: true,\n content: [\n {\n type: \"text\",\n text: `Unknown tool: ${req.params.name}`,\n },\n ],\n };\n }\n\n try {\n const data = await tool.handler(req.params.arguments ?? {});\n const text =\n typeof data === \"string\" ? data : JSON.stringify(data, null, 2);\n return {\n content: [{ type: \"text\", text }],\n };\n } catch (err) {\n const msg =\n err instanceof PropLineHTTPError\n ? `PropLine API error ${err.statusCode}: ${err.body.slice(0, 500)}`\n : err instanceof Error\n ? err.message\n : String(err);\n return {\n isError: true,\n content: [{ type: \"text\", text: msg }],\n };\n }\n});\n\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\n// stderr is fine in MCP — clients route it to logs without breaking the\n// JSON-RPC stream on stdout.\nconsole.error(`[propline-mcp ${VERSION}] connected via stdio`);\n","/**\n * Thin REST client for the PropLine API. Mirrors the public surface of\n * the `propline` npm package but kept inline here so the MCP server has\n * zero non-MCP runtime dependencies (the official SDK is the right choice\n * for application code; MCP servers want the tightest possible install).\n */\n\nconst DEFAULT_BASE_URL = \"https://api.prop-line.com\";\n\nexport class PropLineHTTPError extends Error {\n constructor(public statusCode: number, public body: string) {\n super(`PropLine HTTP ${statusCode}: ${body.slice(0, 200)}`);\n this.name = \"PropLineHTTPError\";\n }\n}\n\nexport interface ClientOptions {\n apiKey: string;\n baseUrl?: string;\n timeoutMs?: number;\n}\n\nexport class PropLineClient {\n private readonly apiKey: string;\n private readonly baseUrl: string;\n private readonly timeoutMs: number;\n\n constructor(opts: ClientOptions) {\n if (!opts.apiKey) {\n throw new Error(\n \"PROPLINE_API_KEY is required. Get one at https://prop-line.com\",\n );\n }\n this.apiKey = opts.apiKey;\n this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, \"\");\n this.timeoutMs = opts.timeoutMs ?? 20_000;\n }\n\n private async request<T = unknown>(\n path: string,\n query: Record<string, string | number | boolean | undefined> = {},\n ): Promise<T> {\n const url = new URL(this.baseUrl + path);\n for (const [k, v] of Object.entries(query)) {\n if (v !== undefined && v !== null && v !== \"\") {\n url.searchParams.set(k, String(v));\n }\n }\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n try {\n const r = await fetch(url, {\n headers: {\n \"X-API-Key\": this.apiKey,\n Accept: \"application/json\",\n \"User-Agent\": \"propline-mcp/0.1.0\",\n },\n signal: controller.signal,\n });\n const text = await r.text();\n if (!r.ok) {\n throw new PropLineHTTPError(r.status, text);\n }\n try {\n return JSON.parse(text) as T;\n } catch {\n return text as unknown as T;\n }\n } finally {\n clearTimeout(timer);\n }\n }\n\n // ----- Discovery -----\n\n listSports(): Promise<unknown> {\n return this.request(\"/v1/sports\");\n }\n\n listEvents(sportKey: string, opts: { live?: boolean } = {}): Promise<unknown> {\n return this.request(`/v1/sports/${sportKey}/events`, {\n live: opts.live ? \"true\" : undefined,\n });\n }\n\n listEventMarkets(sportKey: string, eventId: string | number): Promise<unknown> {\n return this.request(`/v1/sports/${sportKey}/events/${eventId}/markets`);\n }\n\n // ----- Odds -----\n\n getOdds(\n sportKey: string,\n opts: {\n markets?: string;\n bookmakers?: string;\n eventId?: string | number;\n } = {},\n ): Promise<unknown> {\n if (opts.eventId) {\n return this.request(\n `/v1/sports/${sportKey}/events/${opts.eventId}/odds`,\n {\n markets: opts.markets,\n bookmakers: opts.bookmakers,\n },\n );\n }\n return this.request(`/v1/sports/${sportKey}/odds`, {\n markets: opts.markets,\n bookmakers: opts.bookmakers,\n });\n }\n\n getOddsHistory(\n sportKey: string,\n eventId: string | number,\n opts: { markets?: string } = {},\n ): Promise<unknown> {\n return this.request(\n `/v1/sports/${sportKey}/events/${eventId}/odds/history`,\n { markets: opts.markets },\n );\n }\n\n // ----- Scores + stats + resolution -----\n\n getScores(sportKey: string, opts: { daysFrom?: number } = {}): Promise<unknown> {\n return this.request(`/v1/sports/${sportKey}/scores`, {\n daysFrom: opts.daysFrom,\n });\n }\n\n getResolutionSummary(opts: { days?: number } = {}): Promise<unknown> {\n return this.request(`/v1/markets/resolution-summary`, {\n days: opts.days,\n });\n }\n\n getEventStats(sportKey: string, eventId: string | number): Promise<unknown> {\n return this.request(`/v1/sports/${sportKey}/events/${eventId}/stats`);\n }\n\n getEventResults(sportKey: string, eventId: string | number): Promise<unknown> {\n return this.request(`/v1/sports/${sportKey}/events/${eventId}/results`);\n }\n\n // ----- Player history -----\n\n getPlayerHistory(\n sportKey: string,\n playerName: string,\n opts: { limit?: number; markets?: string } = {},\n ): Promise<unknown> {\n return this.request(\n `/v1/sports/${sportKey}/players/${encodeURIComponent(playerName)}/history`,\n { limit: opts.limit, markets: opts.markets },\n );\n }\n\n // ----- Cross-book +EV -----\n\n getEventEv(\n sportKey: string,\n eventId: string | number,\n opts: { markets?: string; minEvPct?: number } = {},\n ): Promise<unknown> {\n return this.request(`/v1/sports/${sportKey}/events/${eventId}/ev`, {\n markets: opts.markets,\n min_ev_pct: opts.minEvPct,\n });\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/client.ts"],"sourcesContent":["/**\n * PropLine MCP server.\n *\n * Exposes the PropLine REST API as Model Context Protocol tools so AI\n * clients (Claude Desktop, Claude Code, ChatGPT desktop with MCP, etc.)\n * can pull live odds, prop resolution, cross-book +EV, scores, and\n * box-score stats directly via tool calls.\n *\n * Run via: npx -y propline-mcp\n * Auth: PROPLINE_API_KEY env var (free key at https://prop-line.com)\n * Optional: PROPLINE_BASE_URL env var (override for self-hosted setups)\n */\n\nimport { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n} from \"@modelcontextprotocol/sdk/types.js\";\n\nimport { PropLineClient, PropLineHTTPError } from \"./client.js\";\n\nexport const VERSION = \"0.3.0\";\n\nconst apiKey = process.env.PROPLINE_API_KEY;\nconst baseUrl = process.env.PROPLINE_BASE_URL;\n\n// The API key is intentionally NOT required at startup. MCP clients and\n// directory crawlers (Glama, the MCP Registry) must be able to introspect\n// the tool list before a key is configured — exiting here would make the\n// server undiscoverable and break the install-then-configure UX. The key\n// is enforced lazily on the first real tool call instead; tools/list never\n// touches the client.\nlet _client: PropLineClient | null = null;\nfunction client(): PropLineClient {\n if (!_client) {\n if (!apiKey) {\n throw new Error(\n \"PROPLINE_API_KEY is not set. Get a free key at \" +\n \"https://prop-line.com and add it to your MCP client config \" +\n \"(env var: PROPLINE_API_KEY).\",\n );\n }\n _client = new PropLineClient({ apiKey, baseUrl });\n }\n return _client;\n}\n\n// ---------------------------------------------------------------------\n// Tool definitions\n// ---------------------------------------------------------------------\n\ninterface ToolDef {\n name: string;\n description: string;\n inputSchema: {\n type: \"object\";\n properties: Record<string, unknown>;\n required?: string[];\n additionalProperties?: boolean;\n };\n // Returns either JSON-serializable data (will be JSON.stringify'd in the\n // tool result) or a string (returned as-is).\n handler: (args: Record<string, unknown>) => Promise<unknown>;\n}\n\nconst tools: ToolDef[] = [\n {\n name: \"propline_list_sports\",\n description:\n \"List all sports PropLine currently polls. Returns sport keys \" +\n \"(e.g. baseball_mlb, basketball_nba, soccer_epl) along with human \" +\n \"titles and active status. Use this first to discover what \" +\n \"sport_key values are valid for the other tools.\",\n inputSchema: {\n type: \"object\",\n properties: {},\n additionalProperties: false,\n },\n handler: () => client().listSports(),\n },\n {\n name: \"propline_list_events\",\n description:\n \"List upcoming events for a sport. Returns each event's id, \" +\n \"home_team, away_team, commence_time. Use the returned event_id \" +\n \"to drill into per-event odds, props, +EV, or results.\",\n inputSchema: {\n type: \"object\",\n properties: {\n sport_key: {\n type: \"string\",\n description:\n \"Sport key from propline_list_sports — e.g. baseball_mlb, basketball_nba\",\n },\n live: {\n type: \"boolean\",\n description:\n \"If true, only return in-progress (live) events. Defaults to false.\",\n },\n },\n required: [\"sport_key\"],\n additionalProperties: false,\n },\n handler: (args) =>\n client().listEvents(args.sport_key as string, {\n live: args.live as boolean | undefined,\n }),\n },\n {\n name: \"propline_list_event_markets\",\n description:\n \"List the market types available for a specific event (e.g. h2h, \" +\n \"spreads, totals, player_points, pitcher_strikeouts). Useful when \" +\n \"you don't know which prop markets a given event carries.\",\n inputSchema: {\n type: \"object\",\n properties: {\n sport_key: { type: \"string\" },\n event_id: { type: [\"string\", \"number\"] },\n },\n required: [\"sport_key\", \"event_id\"],\n additionalProperties: false,\n },\n handler: (args) =>\n client().listEventMarkets(\n args.sport_key as string,\n args.event_id as string | number,\n ),\n },\n {\n name: \"propline_get_odds\",\n description:\n \"Get live odds. If event_id is supplied, returns full per-event \" +\n \"props for that event; otherwise returns bulk game-line odds for \" +\n \"the whole sport. Pass markets as a comma-separated list (e.g. \" +\n \"'h2h,spreads,totals' or 'player_points,player_rebounds'). \" +\n \"Response includes a bookmakers[] array across every book that \" +\n \"carries the requested markets (currently up to 13: Bovada, \" +\n \"DraftKings, FanDuel, Pinnacle, BetMGM, BetRivers, Unibet, \" +\n \"Underdog, PrizePicks, Kalshi, Polymarket, Matchbook, Smarkets \" +\n \"— coverage varies by sport).\",\n inputSchema: {\n type: \"object\",\n properties: {\n sport_key: { type: \"string\" },\n event_id: {\n type: [\"string\", \"number\"],\n description: \"Optional. If set, returns props for this event.\",\n },\n markets: {\n type: \"string\",\n description:\n \"Comma-separated market keys. Defaults to h2h on bulk; h2h,spreads,totals on event. Pass an explicit list to fetch player props (sport-specific — e.g. player_points,player_rebounds for NBA; pitcher_strikeouts,batter_home_runs for MLB).\",\n },\n bookmakers: {\n type: \"string\",\n description:\n \"Comma-separated subset of book keys (bovada, draftkings, fanduel, pinnacle, betmgm, betrivers, unibet, underdog, prizepicks, kalshi, polymarket, matchbook, smarkets). Default returns all available.\",\n },\n },\n required: [\"sport_key\"],\n additionalProperties: false,\n },\n handler: (args) =>\n client().getOdds(args.sport_key as string, {\n eventId: args.event_id as string | number | undefined,\n markets: args.markets as string | undefined,\n bookmakers: args.bookmakers as string | undefined,\n }),\n },\n {\n name: \"propline_get_odds_history\",\n description:\n \"Pro-tier endpoint. Returns the historical line-movement snapshot \" +\n \"series for an event (every recorded price/point change per \" +\n \"outcome over the event's lifetime). Free tier returns market \" +\n \"structure with redacted snapshots and an upgrade pointer.\",\n inputSchema: {\n type: \"object\",\n properties: {\n sport_key: { type: \"string\" },\n event_id: { type: [\"string\", \"number\"] },\n markets: { type: \"string\" },\n },\n required: [\"sport_key\", \"event_id\"],\n additionalProperties: false,\n },\n handler: (args) =>\n client().getOddsHistory(\n args.sport_key as string,\n args.event_id as string | number,\n { markets: args.markets as string | undefined },\n ),\n },\n {\n name: \"propline_get_scores\",\n description:\n \"Free-tier endpoint. Returns recent and live game scores plus \" +\n \"status (scheduled, live, final) for a sport. Useful for: 'is \" +\n \"this game over yet, what was the final score'.\",\n inputSchema: {\n type: \"object\",\n properties: {\n sport_key: { type: \"string\" },\n days_from: {\n type: \"number\",\n description:\n \"How many past days of completed games to include. Defaults to 1.\",\n },\n },\n required: [\"sport_key\"],\n additionalProperties: false,\n },\n handler: (args) =>\n client().getScores(args.sport_key as string, {\n daysFrom: args.days_from as number | undefined,\n }),\n },\n {\n name: \"propline_get_mlb_grand_salami\",\n description:\n \"Free-tier endpoint. Returns the synthetic daily MLB Grand Salami \" +\n \"for a given UTC date — total runs scored across every MLB game \" +\n \"on the slate plus each book's implied Grand Salami line (median \" +\n \"of per-game primary totals across our MLB books incl. Pinnacle, \" +\n \"Polymarket, Matchbook, Smarkets). No retail sportsbook quotes \" +\n \"this as a single market. Useful for: 'what's the total run line \" +\n \"for tonight's full MLB slate', 'did the Grand Salami go over \" +\n \"yesterday', 'historical Grand Salami results for backtesting'.\",\n inputSchema: {\n type: \"object\",\n properties: {\n date: {\n type: \"string\",\n description:\n \"YYYY-MM-DD UTC date. Defaults to today (UTC) when omitted.\",\n },\n },\n required: [],\n additionalProperties: false,\n },\n handler: (args) =>\n client().getMlbGrandSalami({\n date: args.date as string | undefined,\n }),\n },\n {\n name: \"propline_get_resolution_summary\",\n description:\n \"Free-tier endpoint. Returns the factual volume of player props \" +\n \"PropLine has graded against real box scores over the last N days \" +\n \"(aggregated counts only): total graded/settled, games, sports \" +\n \"covered, plus per-sport and top-market breakdowns. Useful for: \" +\n \"'how much graded prop data does PropLine have, what's the \" +\n \"coverage'. A coverage proof, never a profitability claim.\",\n inputSchema: {\n type: \"object\",\n properties: {\n days: {\n type: \"number\",\n description: \"Look-back window, 1-90. Defaults to 30.\",\n },\n },\n required: [],\n additionalProperties: false,\n },\n handler: (args) =>\n client().getResolutionSummary({ days: args.days as number | undefined }),\n },\n {\n name: \"propline_get_event_stats\",\n description:\n \"Book-agnostic raw box-score stats for a completed event. Returns \" +\n \"per-player stats (e.g. strikeouts, hits, points, rebounds, \" +\n \"shots-on-goal) decoupled from any sportsbook's lines. Free tier.\",\n inputSchema: {\n type: \"object\",\n properties: {\n sport_key: { type: \"string\" },\n event_id: { type: [\"string\", \"number\"] },\n },\n required: [\"sport_key\", \"event_id\"],\n additionalProperties: false,\n },\n handler: (args) =>\n client().getEventStats(\n args.sport_key as string,\n args.event_id as string | number,\n ),\n },\n {\n name: \"propline_get_event_results\",\n description:\n \"Pro-tier endpoint. Returns graded prop outcomes for a completed \" +\n \"event — every Over/Under marked won, lost, push, or void with \" +\n \"the actual stat value next to the line. The single most \" +\n \"distinctive feature vs the-odds-api: they don't grade props at \" +\n \"any tier. Free tier returns the same structure with resolution \" +\n \"and actual_value redacted plus an upgrade pointer.\",\n inputSchema: {\n type: \"object\",\n properties: {\n sport_key: { type: \"string\" },\n event_id: { type: [\"string\", \"number\"] },\n },\n required: [\"sport_key\", \"event_id\"],\n additionalProperties: false,\n },\n handler: (args) =>\n client().getEventResults(\n args.sport_key as string,\n args.event_id as string | number,\n ),\n },\n {\n name: \"propline_get_player_history\",\n description:\n \"Player prop history across recent games. Returns each prior prop \" +\n \"this player took with line, prices, resolution, and actual value. \" +\n \"Pro tier returns full data; free tier returns redacted \" +\n \"resolution/actual_value with an upgrade pointer.\",\n inputSchema: {\n type: \"object\",\n properties: {\n sport_key: { type: \"string\" },\n player_name: {\n type: \"string\",\n description:\n \"Player name as it appears in box scores — e.g. 'Aaron Judge', 'Nikola Jokic'\",\n },\n limit: {\n type: \"number\",\n description: \"Max number of past games (default 20, max 100)\",\n },\n markets: {\n type: \"string\",\n description:\n \"Comma-separated subset of markets (e.g. 'player_points,player_rebounds')\",\n },\n },\n required: [\"sport_key\", \"player_name\"],\n additionalProperties: false,\n },\n handler: (args) =>\n client().getPlayerHistory(\n args.sport_key as string,\n args.player_name as string,\n {\n limit: args.limit as number | undefined,\n markets: args.markets as string | undefined,\n },\n ),\n },\n {\n name: \"propline_get_event_ev\",\n description:\n \"Pro-tier endpoint. Returns cross-book +EV per outcome for an \" +\n \"event. We anchor on Pinnacle's sharp line, remove vig, derive a \" +\n \"no-vig fair line, and compute EV% per book at the same line. \" +\n \"Outcomes are sorted with +EV plays floated to the top of each \" +\n \"line group. PrizePicks is excluded from EV math (DFS payouts \" +\n \"aren't comparable to per-book prices).\",\n inputSchema: {\n type: \"object\",\n properties: {\n sport_key: { type: \"string\" },\n event_id: { type: [\"string\", \"number\"] },\n markets: { type: \"string\" },\n min_ev_pct: {\n type: \"number\",\n description: \"Filter to outcomes with EV ≥ this percent (e.g. 2.0).\",\n },\n },\n required: [\"sport_key\", \"event_id\"],\n additionalProperties: false,\n },\n handler: (args) =>\n client().getEventEv(\n args.sport_key as string,\n args.event_id as string | number,\n {\n markets: args.markets as string | undefined,\n minEvPct: args.min_ev_pct as number | undefined,\n },\n ),\n },\n];\n\n// ---------------------------------------------------------------------\n// MCP server wiring\n// ---------------------------------------------------------------------\n\nconst server = new Server(\n { name: \"propline-mcp\", version: VERSION },\n { capabilities: { tools: {} } },\n);\n\nserver.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools: tools.map((t) => ({\n name: t.name,\n description: t.description,\n inputSchema: t.inputSchema,\n })),\n}));\n\nserver.setRequestHandler(CallToolRequestSchema, async (req) => {\n const tool = tools.find((t) => t.name === req.params.name);\n if (!tool) {\n return {\n isError: true,\n content: [\n {\n type: \"text\",\n text: `Unknown tool: ${req.params.name}`,\n },\n ],\n };\n }\n\n try {\n const data = await tool.handler(req.params.arguments ?? {});\n const text =\n typeof data === \"string\" ? data : JSON.stringify(data, null, 2);\n return {\n content: [{ type: \"text\", text }],\n };\n } catch (err) {\n const msg =\n err instanceof PropLineHTTPError\n ? `PropLine API error ${err.statusCode}: ${err.body.slice(0, 500)}`\n : err instanceof Error\n ? err.message\n : String(err);\n return {\n isError: true,\n content: [{ type: \"text\", text: msg }],\n };\n }\n});\n\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\n// stderr is fine in MCP — clients route it to logs without breaking the\n// JSON-RPC stream on stdout.\nconsole.error(`[propline-mcp ${VERSION}] connected via stdio`);\nif (!apiKey) {\n console.error(\n \"[propline-mcp] note: PROPLINE_API_KEY is not set. Tools are listed \" +\n \"for discovery, but any tool call will error until you configure it. \" +\n \"Free key: https://prop-line.com\",\n );\n}\n","/**\n * Thin REST client for the PropLine API. Mirrors the public surface of\n * the `propline` npm package but kept inline here so the MCP server has\n * zero non-MCP runtime dependencies (the official SDK is the right choice\n * for application code; MCP servers want the tightest possible install).\n */\n\nconst DEFAULT_BASE_URL = \"https://api.prop-line.com\";\n\nexport class PropLineHTTPError extends Error {\n constructor(public statusCode: number, public body: string) {\n super(`PropLine HTTP ${statusCode}: ${body.slice(0, 200)}`);\n this.name = \"PropLineHTTPError\";\n }\n}\n\nexport interface ClientOptions {\n apiKey: string;\n baseUrl?: string;\n timeoutMs?: number;\n}\n\nexport class PropLineClient {\n private readonly apiKey: string;\n private readonly baseUrl: string;\n private readonly timeoutMs: number;\n\n constructor(opts: ClientOptions) {\n if (!opts.apiKey) {\n throw new Error(\n \"PROPLINE_API_KEY is required. Get one at https://prop-line.com\",\n );\n }\n this.apiKey = opts.apiKey;\n this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, \"\");\n this.timeoutMs = opts.timeoutMs ?? 20_000;\n }\n\n private async request<T = unknown>(\n path: string,\n query: Record<string, string | number | boolean | undefined> = {},\n ): Promise<T> {\n const url = new URL(this.baseUrl + path);\n for (const [k, v] of Object.entries(query)) {\n if (v !== undefined && v !== null && v !== \"\") {\n url.searchParams.set(k, String(v));\n }\n }\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n try {\n const r = await fetch(url, {\n headers: {\n \"X-API-Key\": this.apiKey,\n Accept: \"application/json\",\n \"User-Agent\": \"propline-mcp/0.1.0\",\n },\n signal: controller.signal,\n });\n const text = await r.text();\n if (!r.ok) {\n throw new PropLineHTTPError(r.status, text);\n }\n try {\n return JSON.parse(text) as T;\n } catch {\n return text as unknown as T;\n }\n } finally {\n clearTimeout(timer);\n }\n }\n\n // ----- Discovery -----\n\n listSports(): Promise<unknown> {\n return this.request(\"/v1/sports\");\n }\n\n listEvents(sportKey: string, opts: { live?: boolean } = {}): Promise<unknown> {\n return this.request(`/v1/sports/${sportKey}/events`, {\n live: opts.live ? \"true\" : undefined,\n });\n }\n\n listEventMarkets(sportKey: string, eventId: string | number): Promise<unknown> {\n return this.request(`/v1/sports/${sportKey}/events/${eventId}/markets`);\n }\n\n // ----- Odds -----\n\n getOdds(\n sportKey: string,\n opts: {\n markets?: string;\n bookmakers?: string;\n eventId?: string | number;\n } = {},\n ): Promise<unknown> {\n if (opts.eventId) {\n return this.request(\n `/v1/sports/${sportKey}/events/${opts.eventId}/odds`,\n {\n markets: opts.markets,\n bookmakers: opts.bookmakers,\n },\n );\n }\n return this.request(`/v1/sports/${sportKey}/odds`, {\n markets: opts.markets,\n bookmakers: opts.bookmakers,\n });\n }\n\n getOddsHistory(\n sportKey: string,\n eventId: string | number,\n opts: { markets?: string } = {},\n ): Promise<unknown> {\n return this.request(\n `/v1/sports/${sportKey}/events/${eventId}/odds/history`,\n { markets: opts.markets },\n );\n }\n\n // ----- Scores + stats + resolution -----\n\n getScores(sportKey: string, opts: { daysFrom?: number } = {}): Promise<unknown> {\n return this.request(`/v1/sports/${sportKey}/scores`, {\n daysFrom: opts.daysFrom,\n });\n }\n\n getMlbGrandSalami(opts: { date?: string } = {}): Promise<unknown> {\n return this.request(`/v1/sports/baseball_mlb/grand-salami`, {\n date: opts.date,\n });\n }\n\n getResolutionSummary(opts: { days?: number } = {}): Promise<unknown> {\n return this.request(`/v1/markets/resolution-summary`, {\n days: opts.days,\n });\n }\n\n getEventStats(sportKey: string, eventId: string | number): Promise<unknown> {\n return this.request(`/v1/sports/${sportKey}/events/${eventId}/stats`);\n }\n\n getEventResults(sportKey: string, eventId: string | number): Promise<unknown> {\n return this.request(`/v1/sports/${sportKey}/events/${eventId}/results`);\n }\n\n // ----- Player history -----\n\n getPlayerHistory(\n sportKey: string,\n playerName: string,\n opts: { limit?: number; markets?: string } = {},\n ): Promise<unknown> {\n return this.request(\n `/v1/sports/${sportKey}/players/${encodeURIComponent(playerName)}/history`,\n { limit: opts.limit, markets: opts.markets },\n );\n }\n\n // ----- Cross-book +EV -----\n\n getEventEv(\n sportKey: string,\n eventId: string | number,\n opts: { markets?: string; minEvPct?: number } = {},\n ): Promise<unknown> {\n return this.request(`/v1/sports/${sportKey}/events/${eventId}/ev`, {\n markets: opts.markets,\n min_ev_pct: opts.minEvPct,\n });\n }\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "propline-mcp",
3
- "version": "0.2.2",
3
+ "version": "0.3.0",
4
4
  "mcpName": "io.github.proplineapi/propline-mcp",
5
5
  "description": "Model Context Protocol server for the PropLine player props betting odds API. Exposes live odds, prop resolution, cross-book +EV, scores, and box-score stats as tool calls for Claude Desktop, Claude Code, and any MCP-compatible client.",
6
6
  "keywords": [