odds-api-mcp-server 1.1.0 → 1.2.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/README.md +117 -60
- package/dist/index.js +67 -18
- package/package.json +3 -2
- package/src/index.test.ts +56 -2
- package/src/index.ts +72 -1
package/README.md
CHANGED
|
@@ -4,11 +4,11 @@ Model Context Protocol (MCP) server for [Odds-API.io](https://odds-api.io) - pro
|
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
- **
|
|
7
|
+
- **21 API tools** covering the full Odds-API.io v3 surface: sports, events, odds, historical data, value bets, arbitrage, and more
|
|
8
8
|
- **Documentation resources** for AI context
|
|
9
|
-
- **Real-time data** from 265 bookmakers across 34 sports
|
|
9
|
+
- **Real-time data** from 265+ bookmakers across 34 sports
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Quick Start
|
|
12
12
|
|
|
13
13
|
### Claude Code CLI
|
|
14
14
|
|
|
@@ -16,32 +16,27 @@ Model Context Protocol (MCP) server for [Odds-API.io](https://odds-api.io) - pro
|
|
|
16
16
|
claude mcp add odds-api --env ODDS_API_KEY="your-api-key" -- npx -y odds-api-mcp-server
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
###
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
npm install -g odds-api-mcp-server
|
|
23
|
-
```
|
|
19
|
+
### Claude Desktop
|
|
24
20
|
|
|
25
|
-
|
|
21
|
+
Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS, `%APPDATA%\Claude\claude_desktop_config.json` on Windows):
|
|
26
22
|
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"mcpServers": {
|
|
26
|
+
"odds-api": {
|
|
27
|
+
"command": "npx",
|
|
28
|
+
"args": ["-y", "odds-api-mcp-server"],
|
|
29
|
+
"env": {
|
|
30
|
+
"ODDS_API_KEY": "your-api-key"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
32
35
|
```
|
|
33
36
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
### Environment Variables
|
|
37
|
-
|
|
38
|
-
- `ODDS_API_KEY` (required): Your Odds-API.io API key
|
|
39
|
-
|
|
40
|
-
Get your API key at [odds-api.io](https://odds-api.io).
|
|
41
|
-
|
|
42
|
-
### Claude Desktop
|
|
37
|
+
### Cursor
|
|
43
38
|
|
|
44
|
-
Add to your
|
|
39
|
+
Add to your Cursor MCP settings (`.cursor/mcp.json` in your project or global config):
|
|
45
40
|
|
|
46
41
|
```json
|
|
47
42
|
{
|
|
@@ -57,67 +52,128 @@ Add to your Claude Desktop config (`~/.config/claude/claude_desktop_config.json`
|
|
|
57
52
|
}
|
|
58
53
|
```
|
|
59
54
|
|
|
60
|
-
###
|
|
55
|
+
### VS Code
|
|
61
56
|
|
|
62
|
-
Add to your
|
|
57
|
+
Add to your VS Code settings (`.vscode/mcp.json`):
|
|
63
58
|
|
|
64
59
|
```json
|
|
65
60
|
{
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
"
|
|
61
|
+
"servers": {
|
|
62
|
+
"odds-api": {
|
|
63
|
+
"command": "npx",
|
|
64
|
+
"args": ["-y", "odds-api-mcp-server"],
|
|
65
|
+
"env": {
|
|
66
|
+
"ODDS_API_KEY": "your-api-key"
|
|
67
|
+
}
|
|
71
68
|
}
|
|
72
69
|
}
|
|
73
70
|
}
|
|
74
71
|
```
|
|
75
72
|
|
|
73
|
+
### Global Install (alternative)
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
npm install -g odds-api-mcp-server
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Then use `odds-api-mcp` as the command instead of `npx -y odds-api-mcp-server`.
|
|
80
|
+
|
|
81
|
+
## Configuration
|
|
82
|
+
|
|
83
|
+
| Variable | Required | Description |
|
|
84
|
+
|----------|----------|-------------|
|
|
85
|
+
| `ODDS_API_KEY` | Yes | Your API key from [odds-api.io](https://odds-api.io) |
|
|
86
|
+
|
|
76
87
|
## Available Tools
|
|
77
88
|
|
|
89
|
+
### Sports & Leagues
|
|
90
|
+
|
|
91
|
+
| Tool | Description |
|
|
92
|
+
|------|-------------|
|
|
93
|
+
| `get_sports` | List all available sports with slugs |
|
|
94
|
+
| `get_leagues` | Get leagues for a sport (with optional `all` flag for inactive leagues) |
|
|
95
|
+
|
|
96
|
+
### Bookmakers
|
|
97
|
+
|
|
98
|
+
| Tool | Description |
|
|
99
|
+
|------|-------------|
|
|
100
|
+
| `get_bookmakers` | List all supported bookmakers |
|
|
101
|
+
| `get_selected_bookmakers` | Get your currently selected bookmakers |
|
|
102
|
+
| `select_bookmakers` | Add bookmakers to your selection |
|
|
103
|
+
| `clear_selected_bookmakers` | Clear all selected bookmakers (once per 12h) |
|
|
104
|
+
|
|
105
|
+
### Events
|
|
106
|
+
|
|
78
107
|
| Tool | Description |
|
|
79
108
|
|------|-------------|
|
|
80
|
-
| `
|
|
81
|
-
| `
|
|
82
|
-
| `get_leagues` | Get leagues for a sport |
|
|
83
|
-
| `get_events` | Get events with filtering options |
|
|
109
|
+
| `get_events` | Get events with filtering (league, status, date range, participant, bookmaker, pagination) |
|
|
110
|
+
| `get_event` | Get a single event by ID |
|
|
84
111
|
| `get_live_events` | Get currently live events |
|
|
85
|
-
| `search_events` | Search events by text |
|
|
86
|
-
| `get_odds` | Get odds for an event |
|
|
87
|
-
| `get_multi_odds` | Get odds for multiple events (batch) |
|
|
88
|
-
| `get_value_bets` | Get value betting opportunities |
|
|
89
|
-
| `get_arbitrage_bets` | Get arbitrage opportunities |
|
|
90
|
-
| `get_participants` | Get teams/participants |
|
|
91
|
-
| `get_documentation` | Get API documentation |
|
|
112
|
+
| `search_events` | Search events by team name or text |
|
|
92
113
|
|
|
93
|
-
|
|
114
|
+
### Odds
|
|
94
115
|
|
|
95
|
-
|
|
|
96
|
-
|
|
97
|
-
| `
|
|
98
|
-
| `
|
|
116
|
+
| Tool | Description |
|
|
117
|
+
|------|-------------|
|
|
118
|
+
| `get_odds` | Get odds for an event from selected bookmakers |
|
|
119
|
+
| `get_multi_odds` | Get odds for up to 10 events in one call |
|
|
120
|
+
| `get_odds_movements` | Get historical line movements for a market |
|
|
121
|
+
| `get_updated_odds` | Get recently changed odds (polling) |
|
|
122
|
+
|
|
123
|
+
### Historical
|
|
124
|
+
|
|
125
|
+
| Tool | Description |
|
|
126
|
+
|------|-------------|
|
|
127
|
+
| `get_historical_events` | Get finished events for a sport/league/date range |
|
|
128
|
+
| `get_historical_odds` | Get closing odds and scores for finished events |
|
|
129
|
+
|
|
130
|
+
### Betting Analytics
|
|
131
|
+
|
|
132
|
+
| Tool | Description |
|
|
133
|
+
|------|-------------|
|
|
134
|
+
| `get_value_bets` | Get positive EV opportunities for a bookmaker |
|
|
135
|
+
| `get_arbitrage_bets` | Get arbitrage opportunities with optimal stakes |
|
|
136
|
+
|
|
137
|
+
### Participants
|
|
138
|
+
|
|
139
|
+
| Tool | Description |
|
|
140
|
+
|------|-------------|
|
|
141
|
+
| `get_participants` | Get teams/participants for a sport |
|
|
142
|
+
| `get_participant` | Get a single participant by ID |
|
|
143
|
+
|
|
144
|
+
### Reference
|
|
145
|
+
|
|
146
|
+
| Tool | Description |
|
|
147
|
+
|------|-------------|
|
|
148
|
+
| `get_documentation` | Fetch full API documentation |
|
|
149
|
+
|
|
150
|
+
## Resources
|
|
151
|
+
|
|
152
|
+
| Resource URI | Description |
|
|
153
|
+
|-------------|-------------|
|
|
154
|
+
| `odds-api://documentation` | Complete API documentation |
|
|
155
|
+
| `odds-api://openapi` | OpenAPI/Swagger specification |
|
|
99
156
|
|
|
100
157
|
## Example Usage
|
|
101
158
|
|
|
102
|
-
Once configured,
|
|
159
|
+
Once configured, ask your AI assistant things like:
|
|
103
160
|
|
|
104
|
-
- "
|
|
161
|
+
- "What sports are available on Odds-API?"
|
|
105
162
|
- "Show me upcoming Premier League matches"
|
|
106
|
-
- "
|
|
107
|
-
- "
|
|
108
|
-
- "
|
|
163
|
+
- "Get odds for the next Arsenal match from Bet365 and Pinnacle"
|
|
164
|
+
- "Find value bets on Bet365 with event details"
|
|
165
|
+
- "Are there any arbitrage opportunities between Bet365 and Unibet?"
|
|
166
|
+
- "Show me how the odds moved for event 12345 on the spread market"
|
|
167
|
+
- "Get historical results for La Liga in January 2026"
|
|
109
168
|
|
|
110
169
|
## Development
|
|
111
170
|
|
|
112
171
|
```bash
|
|
113
|
-
|
|
172
|
+
git clone https://github.com/odds-api-io/odds-api-mcp-server
|
|
173
|
+
cd odds-api-mcp-server
|
|
114
174
|
npm install
|
|
115
|
-
|
|
116
|
-
# Build
|
|
117
175
|
npm run build
|
|
118
|
-
|
|
119
|
-
# Run in development mode
|
|
120
|
-
npm run dev
|
|
176
|
+
npm test
|
|
121
177
|
```
|
|
122
178
|
|
|
123
179
|
## License
|
|
@@ -127,5 +183,6 @@ MIT
|
|
|
127
183
|
## Links
|
|
128
184
|
|
|
129
185
|
- [Odds-API.io](https://odds-api.io) - Main website
|
|
130
|
-
- [Documentation](https://docs.odds-api.io) - API
|
|
131
|
-
- [
|
|
186
|
+
- [Documentation](https://docs.odds-api.io) - API docs
|
|
187
|
+
- [API Reference](https://api.odds-api.io/v3/docs/index.html) - Swagger/OpenAPI
|
|
188
|
+
- [npm](https://www.npmjs.com/package/odds-api-mcp-server) - Package registry
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
exports.apiRequest = apiRequest;
|
|
6
|
-
exports.jsonResponse = jsonResponse;
|
|
7
|
-
exports.textResponse = textResponse;
|
|
8
|
-
exports.errorResponse = errorResponse;
|
|
9
|
-
const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
|
|
10
|
-
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
11
|
-
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
2
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
12
5
|
// ── Constants ────────────────────────────────────────────────────────────────
|
|
13
6
|
const API_BASE_URL = "https://api2.odds-api.io/v3";
|
|
14
7
|
const DOCS_BASE_URL = "https://docs.odds-api.io";
|
|
@@ -326,6 +319,62 @@ const tools = [
|
|
|
326
319
|
return jsonResponse(await apiRequest("/odds/updated", { since, bookmaker, sport }));
|
|
327
320
|
},
|
|
328
321
|
},
|
|
322
|
+
// ── Dropping Odds ───────────────────────────────────────────────
|
|
323
|
+
{
|
|
324
|
+
name: "get_dropping_odds",
|
|
325
|
+
description: "Get odds that have dropped the most from opening, based on sharp bookmaker data. Useful for tracking where sharp money is moving. Updated every ~10 seconds. Only available on paid plans.",
|
|
326
|
+
inputSchema: {
|
|
327
|
+
type: "object",
|
|
328
|
+
properties: {
|
|
329
|
+
sport: {
|
|
330
|
+
type: "string",
|
|
331
|
+
description: "Sport slug to filter by (e.g., 'football', 'basketball')",
|
|
332
|
+
},
|
|
333
|
+
league: {
|
|
334
|
+
type: "string",
|
|
335
|
+
description: "League slug to filter by (e.g., 'england-premier-league'). Requires sport to also be set.",
|
|
336
|
+
},
|
|
337
|
+
market: {
|
|
338
|
+
type: "string",
|
|
339
|
+
description: "Market type to filter by: 'ML', 'Spread', or 'Totals'",
|
|
340
|
+
},
|
|
341
|
+
timeWindow: {
|
|
342
|
+
type: "string",
|
|
343
|
+
description: "Time window for drop calculation and sorting: 'opening', '12h', '24h', '48h' (default: 'opening')",
|
|
344
|
+
},
|
|
345
|
+
minDrop: {
|
|
346
|
+
type: "number",
|
|
347
|
+
description: "Minimum drop percentage threshold (default: 0)",
|
|
348
|
+
},
|
|
349
|
+
limit: {
|
|
350
|
+
type: "number",
|
|
351
|
+
description: "Results per page, 1-200 (default: 50)",
|
|
352
|
+
},
|
|
353
|
+
page: {
|
|
354
|
+
type: "number",
|
|
355
|
+
description: "Page number, 1-indexed (default: 1)",
|
|
356
|
+
},
|
|
357
|
+
includeEventDetails: {
|
|
358
|
+
type: "boolean",
|
|
359
|
+
description: "Include expanded event details (home, away, date, sport, league) in response",
|
|
360
|
+
},
|
|
361
|
+
},
|
|
362
|
+
required: [],
|
|
363
|
+
},
|
|
364
|
+
async handler(args) {
|
|
365
|
+
const { sport, league, market, timeWindow, minDrop, limit, page, includeEventDetails } = args;
|
|
366
|
+
return jsonResponse(await apiRequest("/dropping-odds", {
|
|
367
|
+
sport,
|
|
368
|
+
league,
|
|
369
|
+
market,
|
|
370
|
+
timeWindow,
|
|
371
|
+
minDrop,
|
|
372
|
+
limit,
|
|
373
|
+
page,
|
|
374
|
+
includeEventDetails: includeEventDetails || undefined,
|
|
375
|
+
}));
|
|
376
|
+
},
|
|
377
|
+
},
|
|
329
378
|
// ── Historical ──────────────────────────────────────────────────
|
|
330
379
|
{
|
|
331
380
|
name: "get_historical_events",
|
|
@@ -488,19 +537,17 @@ const tools = [
|
|
|
488
537
|
},
|
|
489
538
|
},
|
|
490
539
|
];
|
|
491
|
-
exports.tools = tools;
|
|
492
540
|
// ── Server Setup ─────────────────────────────────────────────────────────────
|
|
493
541
|
const toolMap = new Map(tools.map((tool) => [tool.name, tool]));
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
|
|
542
|
+
const server = new Server({ name: "odds-api-mcp", version: "1.1.1" }, { capabilities: { tools: {}, resources: {} } });
|
|
543
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
497
544
|
tools: tools.map(({ name, description, inputSchema }) => ({
|
|
498
545
|
name,
|
|
499
546
|
description,
|
|
500
547
|
inputSchema,
|
|
501
548
|
})),
|
|
502
549
|
}));
|
|
503
|
-
server.setRequestHandler(
|
|
550
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
504
551
|
const { name, arguments: args } = request.params;
|
|
505
552
|
const tool = toolMap.get(name);
|
|
506
553
|
if (!tool) {
|
|
@@ -515,7 +562,7 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
|
515
562
|
}
|
|
516
563
|
});
|
|
517
564
|
// ── Resources ────────────────────────────────────────────────────────────────
|
|
518
|
-
server.setRequestHandler(
|
|
565
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
|
|
519
566
|
resources: [
|
|
520
567
|
{
|
|
521
568
|
uri: "odds-api://documentation",
|
|
@@ -531,7 +578,7 @@ server.setRequestHandler(types_js_1.ListResourcesRequestSchema, async () => ({
|
|
|
531
578
|
},
|
|
532
579
|
],
|
|
533
580
|
}));
|
|
534
|
-
server.setRequestHandler(
|
|
581
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
535
582
|
const { uri } = request.params;
|
|
536
583
|
switch (uri) {
|
|
537
584
|
case "odds-api://documentation": {
|
|
@@ -566,7 +613,7 @@ async function main() {
|
|
|
566
613
|
console.error("Error: ODDS_API_KEY environment variable is required");
|
|
567
614
|
process.exit(1);
|
|
568
615
|
}
|
|
569
|
-
const transport = new
|
|
616
|
+
const transport = new StdioServerTransport();
|
|
570
617
|
await server.connect(transport);
|
|
571
618
|
console.error("Odds-API.io MCP Server running on stdio");
|
|
572
619
|
}
|
|
@@ -574,3 +621,5 @@ main().catch((error) => {
|
|
|
574
621
|
console.error("Fatal error:", error);
|
|
575
622
|
process.exit(1);
|
|
576
623
|
});
|
|
624
|
+
// ── Exports (for testing) ────────────────────────────────────────────────────
|
|
625
|
+
export { tools, toolMap, apiRequest, jsonResponse, textResponse, errorResponse };
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "odds-api-mcp-server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "MCP server for Odds-API.io - Access sports betting odds data from AI tools like Claude, Cursor, and VS Code",
|
|
5
|
+
"type": "module",
|
|
5
6
|
"main": "dist/index.js",
|
|
6
7
|
"bin": {
|
|
7
|
-
"odds-api-mcp": "dist/index.js"
|
|
8
|
+
"odds-api-mcp-server": "dist/index.js"
|
|
8
9
|
},
|
|
9
10
|
"scripts": {
|
|
10
11
|
"build": "tsc",
|
package/src/index.test.ts
CHANGED
|
@@ -63,6 +63,7 @@ describe("Tool Registry", () => {
|
|
|
63
63
|
"get_multi_odds",
|
|
64
64
|
"get_odds_movements",
|
|
65
65
|
"get_updated_odds",
|
|
66
|
+
"get_dropping_odds",
|
|
66
67
|
"get_historical_events",
|
|
67
68
|
"get_historical_odds",
|
|
68
69
|
"get_value_bets",
|
|
@@ -72,8 +73,8 @@ describe("Tool Registry", () => {
|
|
|
72
73
|
"get_documentation",
|
|
73
74
|
];
|
|
74
75
|
|
|
75
|
-
it("has all
|
|
76
|
-
expect(tools).toHaveLength(
|
|
76
|
+
it("has all 22 tools registered", () => {
|
|
77
|
+
expect(tools).toHaveLength(22);
|
|
77
78
|
});
|
|
78
79
|
|
|
79
80
|
it("has no duplicate tool names", () => {
|
|
@@ -134,6 +135,7 @@ describe("Tool Schemas - Required Parameters", () => {
|
|
|
134
135
|
["get_multi_odds", ["eventIds", "bookmakers"]],
|
|
135
136
|
["get_odds_movements", ["eventId", "bookmaker", "market"]],
|
|
136
137
|
["get_updated_odds", ["since", "bookmaker", "sport"]],
|
|
138
|
+
["get_dropping_odds", []],
|
|
137
139
|
["get_historical_events", ["sport", "league", "from", "to"]],
|
|
138
140
|
["get_historical_odds", ["eventId", "bookmakers"]],
|
|
139
141
|
["get_value_bets", ["bookmaker"]],
|
|
@@ -459,6 +461,58 @@ describe("Tool Handlers", () => {
|
|
|
459
461
|
expect(calledUrl.searchParams.get("since")).toBe(String(since));
|
|
460
462
|
});
|
|
461
463
|
|
|
464
|
+
it("get_dropping_odds passes all optional params", async () => {
|
|
465
|
+
const fetchMock = mockFetchJson([]);
|
|
466
|
+
globalThis.fetch = fetchMock;
|
|
467
|
+
|
|
468
|
+
await toolMap.get("get_dropping_odds")!.handler({
|
|
469
|
+
sport: "football",
|
|
470
|
+
league: "england-premier-league",
|
|
471
|
+
market: "ML",
|
|
472
|
+
timeWindow: "12h",
|
|
473
|
+
minDrop: 5,
|
|
474
|
+
limit: 100,
|
|
475
|
+
page: 2,
|
|
476
|
+
includeEventDetails: true,
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
const calledUrl = new URL(fetchMock.mock.calls[0][0]);
|
|
480
|
+
expect(calledUrl.pathname).toBe("/v3/dropping-odds");
|
|
481
|
+
expect(calledUrl.searchParams.get("sport")).toBe("football");
|
|
482
|
+
expect(calledUrl.searchParams.get("league")).toBe("england-premier-league");
|
|
483
|
+
expect(calledUrl.searchParams.get("market")).toBe("ML");
|
|
484
|
+
expect(calledUrl.searchParams.get("timeWindow")).toBe("12h");
|
|
485
|
+
expect(calledUrl.searchParams.get("minDrop")).toBe("5");
|
|
486
|
+
expect(calledUrl.searchParams.get("limit")).toBe("100");
|
|
487
|
+
expect(calledUrl.searchParams.get("page")).toBe("2");
|
|
488
|
+
expect(calledUrl.searchParams.get("includeEventDetails")).toBe("true");
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
it("get_dropping_odds sends includeEventDetails only when true", async () => {
|
|
492
|
+
const fetchMock = mockFetchJson([]);
|
|
493
|
+
globalThis.fetch = fetchMock;
|
|
494
|
+
|
|
495
|
+
await toolMap.get("get_dropping_odds")!.handler({ includeEventDetails: false });
|
|
496
|
+
const url = new URL(fetchMock.mock.calls[0][0]);
|
|
497
|
+
expect(url.searchParams.has("includeEventDetails")).toBe(false);
|
|
498
|
+
|
|
499
|
+
await toolMap.get("get_dropping_odds")!.handler({});
|
|
500
|
+
const url2 = new URL(fetchMock.mock.calls[1][0]);
|
|
501
|
+
expect(url2.searchParams.has("includeEventDetails")).toBe(false);
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
it("get_dropping_odds works with no params", async () => {
|
|
505
|
+
const fetchMock = mockFetchJson([]);
|
|
506
|
+
globalThis.fetch = fetchMock;
|
|
507
|
+
|
|
508
|
+
await toolMap.get("get_dropping_odds")!.handler({});
|
|
509
|
+
|
|
510
|
+
const calledUrl = new URL(fetchMock.mock.calls[0][0]);
|
|
511
|
+
expect(calledUrl.pathname).toBe("/v3/dropping-odds");
|
|
512
|
+
expect(calledUrl.searchParams.has("sport")).toBe(false);
|
|
513
|
+
expect(calledUrl.searchParams.has("league")).toBe(false);
|
|
514
|
+
});
|
|
515
|
+
|
|
462
516
|
it("get_historical_events passes all required params", async () => {
|
|
463
517
|
const fetchMock = mockFetchJson([]);
|
|
464
518
|
globalThis.fetch = fetchMock;
|
package/src/index.ts
CHANGED
|
@@ -408,6 +408,77 @@ const tools: ToolDefinition[] = [
|
|
|
408
408
|
},
|
|
409
409
|
},
|
|
410
410
|
|
|
411
|
+
// ── Dropping Odds ───────────────────────────────────────────────
|
|
412
|
+
|
|
413
|
+
{
|
|
414
|
+
name: "get_dropping_odds",
|
|
415
|
+
description:
|
|
416
|
+
"Get odds that have dropped the most from opening, based on sharp bookmaker data. Useful for tracking where sharp money is moving. Updated every ~10 seconds. Only available on paid plans.",
|
|
417
|
+
inputSchema: {
|
|
418
|
+
type: "object",
|
|
419
|
+
properties: {
|
|
420
|
+
sport: {
|
|
421
|
+
type: "string",
|
|
422
|
+
description: "Sport slug to filter by (e.g., 'football', 'basketball')",
|
|
423
|
+
},
|
|
424
|
+
league: {
|
|
425
|
+
type: "string",
|
|
426
|
+
description: "League slug to filter by (e.g., 'england-premier-league'). Requires sport to also be set.",
|
|
427
|
+
},
|
|
428
|
+
market: {
|
|
429
|
+
type: "string",
|
|
430
|
+
description: "Market type to filter by: 'ML', 'Spread', or 'Totals'",
|
|
431
|
+
},
|
|
432
|
+
timeWindow: {
|
|
433
|
+
type: "string",
|
|
434
|
+
description: "Time window for drop calculation and sorting: 'opening', '12h', '24h', '48h' (default: 'opening')",
|
|
435
|
+
},
|
|
436
|
+
minDrop: {
|
|
437
|
+
type: "number",
|
|
438
|
+
description: "Minimum drop percentage threshold (default: 0)",
|
|
439
|
+
},
|
|
440
|
+
limit: {
|
|
441
|
+
type: "number",
|
|
442
|
+
description: "Results per page, 1-200 (default: 50)",
|
|
443
|
+
},
|
|
444
|
+
page: {
|
|
445
|
+
type: "number",
|
|
446
|
+
description: "Page number, 1-indexed (default: 1)",
|
|
447
|
+
},
|
|
448
|
+
includeEventDetails: {
|
|
449
|
+
type: "boolean",
|
|
450
|
+
description: "Include expanded event details (home, away, date, sport, league) in response",
|
|
451
|
+
},
|
|
452
|
+
},
|
|
453
|
+
required: [],
|
|
454
|
+
},
|
|
455
|
+
async handler(args) {
|
|
456
|
+
const { sport, league, market, timeWindow, minDrop, limit, page, includeEventDetails } =
|
|
457
|
+
args as {
|
|
458
|
+
sport?: string;
|
|
459
|
+
league?: string;
|
|
460
|
+
market?: string;
|
|
461
|
+
timeWindow?: string;
|
|
462
|
+
minDrop?: number;
|
|
463
|
+
limit?: number;
|
|
464
|
+
page?: number;
|
|
465
|
+
includeEventDetails?: boolean;
|
|
466
|
+
};
|
|
467
|
+
return jsonResponse(
|
|
468
|
+
await apiRequest("/dropping-odds", {
|
|
469
|
+
sport,
|
|
470
|
+
league,
|
|
471
|
+
market,
|
|
472
|
+
timeWindow,
|
|
473
|
+
minDrop,
|
|
474
|
+
limit,
|
|
475
|
+
page,
|
|
476
|
+
includeEventDetails: includeEventDetails || undefined,
|
|
477
|
+
}),
|
|
478
|
+
);
|
|
479
|
+
},
|
|
480
|
+
},
|
|
481
|
+
|
|
411
482
|
// ── Historical ──────────────────────────────────────────────────
|
|
412
483
|
|
|
413
484
|
{
|
|
@@ -609,7 +680,7 @@ const tools: ToolDefinition[] = [
|
|
|
609
680
|
const toolMap = new Map(tools.map((tool) => [tool.name, tool]));
|
|
610
681
|
|
|
611
682
|
const server = new Server(
|
|
612
|
-
{ name: "odds-api-mcp", version: "1.1.
|
|
683
|
+
{ name: "odds-api-mcp", version: "1.1.1" },
|
|
613
684
|
{ capabilities: { tools: {}, resources: {} } },
|
|
614
685
|
);
|
|
615
686
|
|