football-odds-agent
README.md
# football-odds-agent
An MCP (Model Context Protocol) server that gives any MCP client (Claude Desktop,
Claude Code, etc.) tools to pull live football odds, check a team's recent form,
and flag matches where the bookmaker's implied probability disagrees a lot with
a naive form-based estimate.
## Why this project
I'm an economics student — market efficiency in prediction markets (of which
sports betting odds are a textbook example) is a real topic I already understand,
not a borrowed one. This project applies that lens to a live dataset through an
MCP agent, instead of just describing the theory.
**Important honesty note:** `find_value_matches` computes a *disagreement score*
between the market price and a very simple recent-form heuristic. A high score
means "the market and this naive model disagree" — it is **not** a validated
betting edge, and the tool says so in its own output. Real market-efficiency
research would need a much better model, backtesting, and transaction-cost
accounting before any of this could inform a real decision. This project is a
demonstration of MCP tool-calling and data synthesis, not a trading signal.
## Architecture
```
MCP client (e.g. Claude Desktop)
│ calls tools over MCP
▼
server.py (MCPServer, 3 tools)
│
├─ get_upcoming_odds() ──▶ clients/odds_client.py ──▶ the-odds-api.com
├─ get_team_form() ──▶ clients/stats_client.py ──▶ football-data.org
└─ find_value_matches() ──▶ analysis.py (pure functions, fully unit-tested)
combines the two above + flags divergence
```
`analysis.py` has zero I/O — it's pure math (implied probability, overround
removal, a naive form-based estimate, a divergence score) so it can be unit
tested without hitting either API. See `tests/test_analysis.py`.
## Tools exposed
| Tool | What it does |
|---|---|
| `get_upcoming_odds(sport_key)` | Live 1X2 odds for an upcoming league's matches |
| `get_team_form(team_id, last_n)` | A team's win/draw/loss record over its last N matches |
| `find_value_matches(sport_key, team_ids, threshold)` | Cross-references odds + form, flags large disagreements |
## Setup
```bash
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -r requirements.txt
cp .env.example .env # fill in your two free API keys
```
Get free keys (no credit card required for either):
- **ODDS_API_KEY** — [the-odds-api.com](https://the-odds-api.com) (500 credits/month free)
- **FOOTBALL_DATA_API_KEY** — [football-data.org](https://www.football-data.org/client/register) (10 requests/min free)
## Run
```bash
python server.py
```
To use it from Claude Desktop, add it to your MCP server config pointing at
this `server.py`. See the [MCP quickstart](https://modelcontextprotocol.io/quickstart)
for the exact config file location for your OS.
## Test
```bash
pytest tests/ -v
```
10 tests, all pure-logic (no API calls, no network, no keys needed).
## Known limitations
- The form-based probability estimate is deliberately naive (win rate only —
no home/away split, no strength-of-opponent adjustment, no injuries/lineups).
It exists to give the divergence score *something* independent to compare
the market against, not to be predictive on its own.
- `find_value_matches` requires you to manually map match labels to
football-data.org team ids (`team_ids` parameter) — there's no automatic
team-name matching between the two APIs yet.
- Free-tier rate limits (500/day odds, 10/min stats) are enough for exploring
a few leagues, not for scanning every match in every league continuously.
## What I'd do next
- Automatic team-name → team-id resolution between the two APIs.
- A better form model (home/away split, opponent strength, recency weighting).
- Backtest the divergence score against historical results before claiming
any predictive value.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues