# Directory Structure
```
├── .gitignore
├── .python-version
├── main.py
├── odds.py
├── pyproject.toml
├── README.md
└── uv.lock
```
# Files
--------------------------------------------------------------------------------
/.python-version:
--------------------------------------------------------------------------------
```
1 | 3.12
2 |
```
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
```
1 | # Python-generated files
2 | __pycache__/
3 | *.py[oc]
4 | build/
5 | dist/
6 | wheels/
7 | *.egg-info
8 |
9 | # Virtual environments
10 | .venv
11 |
12 | .env
13 |
```
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
```markdown
1 | degen claude.
2 | just need a way for llms to have access to money and place bets...
3 |
4 |
```
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
```python
1 | def main():
2 | print("Hello from degen-mcp!")
3 |
4 |
5 | if __name__ == "__main__":
6 | main()
7 |
```
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
```toml
1 | [project]
2 | name = "degen-mcp"
3 | version = "0.1.0"
4 | description = "Add your description here"
5 | readme = "README.md"
6 | requires-python = ">=3.12"
7 | dependencies = [
8 | "httpx>=0.28.1",
9 | "mcp[cli]>=1.3.0",
10 | ]
11 |
```
--------------------------------------------------------------------------------
/odds.py:
--------------------------------------------------------------------------------
```python
1 | import httpx
2 | import os
3 | from mcp.server.fastmcp import FastMCP
4 | from dotenv import load_dotenv
5 | from typing import Any
6 |
7 | load_dotenv()
8 |
9 | API_KEY = os.getenv("api_key")
10 |
11 | API_BASE_URL = "https://api.the-odds-api.com/v4/sports"
12 | USER_AGENT = "the-odds-api/1.0"
13 | SPORT = 'upcoming' # use the sport_key from the /sports endpoint below, or use 'upcoming' to see the next 8 games across all sports
14 | REGIONS = 'us' # uk | us | eu | au. Multiple can be specified if comma delimited
15 | MARKETS = 'h2h,spreads' # h2h | spreads | totals. Multiple can be specified if comma delimited
16 | ODDS_FORMAT = 'decimal' # decimal | american
17 | DATE_FORMAT = 'iso' # iso | unix
18 | HEADERS = {
19 | "User-Agent": USER_AGENT,
20 | "Accept": "application/json"
21 | }
22 |
23 | #mcp server
24 | mcp = FastMCP("odds")
25 |
26 | async def make_sports_request() -> dict[str, Any] | None:
27 | params = {"api_key": API_KEY}
28 |
29 | async with httpx.AsyncClient() as client:
30 | try:
31 | response = await client.get(API_BASE_URL, headers=HEADERS, params=params, timeout=30.0)
32 | response.raise_for_status()
33 | return response.json()
34 | except Exception:
35 | return None
36 |
37 | async def make_odds_request(sport: str, params: dict) -> dict[str, Any] | None:
38 | url = f'{API_BASE_URL}/{sport}/odds' # corrected url formatting
39 | print('url:: ', url)
40 |
41 | async with httpx.AsyncClient() as client:
42 | try:
43 | response = await client.get(url, headers=HEADERS, params=params, timeout=30.0)
44 | response.raise_for_status()
45 | odds_json = response.json()
46 | print('Remaining requests', response.headers['x-requests-remaining'])
47 | print('Used requests', response.headers['x-requests-used'])
48 | return response.json()
49 | except Exception:
50 | return None
51 |
52 | def print_formatted_odds(odds_data: list[dict]):
53 | """Prints the odds data in a formatted and readable way."""
54 | for game in odds_data:
55 | print(f"Game ID: {game['id']}")
56 | print(f"Sport: {game['sport_title']} ({game['sport_key']})")
57 | print(f"Commence Time: {game['commence_time']}")
58 | print(f"Home Team: {game['home_team']}")
59 | print(f"Away Team: {game['away_team']}")
60 | print("Bookmakers:")
61 |
62 | for bookmaker in game['bookmakers']:
63 | print(f" {bookmaker['title']} ({bookmaker['key']}):")
64 | for market in bookmaker['markets']:
65 | print(f" Market: {market['key']}")
66 | for outcome in market['outcomes']:
67 | if 'point' in outcome:
68 | print(f" {outcome['name']}: Price: {outcome['price']}, Point: {outcome['point']}")
69 | else:
70 | print(f" {outcome['name']}: Price: {outcome['price']}")
71 | print("-" * 40) # Separator between games
72 |
73 | def format_sports_data(sports_data: dict) -> str:
74 | """Format sports data into a readable string."""
75 | return f"""
76 | Key: {sports_data.get('key', 'Unknown')}
77 | Group: {sports_data.get('group', 'Unknown')}
78 | Title: {sports_data.get('title', 'Unknown')}
79 | Description: {sports_data.get('description', 'Unknown')}
80 | Active: {sports_data.get('active', 'Unknown')}
81 | Has Outrights: {sports_data.get('has_outrights', 'Unknown')}
82 | """
83 |
84 | def format_odds_data(odds_data: list[dict]) -> str:
85 | """Formats the odds data into a readable string, similar to the provided example."""
86 | formatted_games = []
87 | for game in odds_data:
88 | game_forecast = f"""
89 | Sport: {game['sport_title']} ({game['sport_key']})
90 | Home Team: {game['home_team']}
91 | Away Team: {game['away_team']}
92 | Commence Time: {game['commence_time']}
93 | """
94 |
95 | bookmaker_forecasts = []
96 | for bookmaker in game['bookmakers']:
97 | bookmaker_info = f" {bookmaker['title']} ({bookmaker['key']}):"
98 | market_forecasts = []
99 | for market in bookmaker['markets']:
100 | market_info = f" Market: {market['key']}"
101 | outcome_forecasts = []
102 | for outcome in market['outcomes']:
103 | if 'point' in outcome:
104 | outcome_info = f" {outcome['name']}: Price: {outcome['price']}, Point: {outcome['point']}"
105 | else:
106 | outcome_info = f" {outcome['name']}: Price: {outcome['price']}"
107 | outcome_forecasts.append(outcome_info)
108 | market_forecast = f"{market_info}\n" + "\n".join(outcome_forecasts)
109 | market_forecasts.append(market_forecast)
110 | bookmaker_forecast = f"{bookmaker_info}\n" + "\n".join(market_forecasts)
111 | bookmaker_forecasts.append(bookmaker_forecast)
112 |
113 | game_forecast += "\n".join(bookmaker_forecasts)
114 | formatted_games.append(game_forecast)
115 | # print_formatted_odds(odds_data)
116 | print(formatted_games)
117 |
118 | return "\n---\n".join(formatted_games)
119 |
120 |
121 | @mcp.tool()
122 | async def get_in_season_sports() -> str:
123 |
124 | sports = await make_sports_request()
125 |
126 | if not sports:
127 | return "failed to get sports"
128 |
129 | results = [format_sports_data(sport) for sport in sports]
130 | return "\n---\n".join(results)
131 |
132 | @mcp.tool()
133 | async def get_odds(sport: str, params: dict) -> str:
134 |
135 | odds_json = await make_odds_request(sport, params)
136 |
137 | if not odds_json:
138 | return "failed to get odds"
139 |
140 | return "\n---\n".join(format_odds_data(odds_json))
141 |
142 |
143 | import asyncio
144 | if __name__ == "__main__":
145 | mcp.run(transport='stdio')
```