Dodi MCPサーバー
コミット 2026年11月7日ドラフト、ラインナップの最適化、ウェイバー申請、トレード交渉を自動化することで、AIエージェントによるESPNファンタジー・フットボール・リーグの管理を可能にします。
別名 HamCops/dodi
- スター
- 1
- ツール
- 26
- ダウンロード数(30日間)
- —
- 最新バージョン
- —
- 最終コミット
- 2026年11月7日
- ライセンス
- MIT
Dodi MCPとは
DodiはMCPサーバーです。 ドラフト、ラインナップの最適化、ウェイバー申請、トレード交渉を自動化することで、AIエージェントによるESPNファンタジー・フットボール・リーグの管理を可能にします。. 26個のツールを提供しており、get_draft_context, next_pick, get_draft_stateなどがあります。
プロジェクトのREADMEから生成された概要
Dodi MCP server について
Dodiは、AIエージェントを通じてESPNファンタジー・フットボール・リーグを管理することを可能にします。このMCP serverは、LLMがリーグと直接対話するためのツールレイヤーを提供し、ライブドラフトや毎週のラインナップ最適化から、ウェイバー申請やトレード交渉まで、あらゆる操作を処理します。リーグの状態を読み取り、選手の価値を数学的に分析し、ロースター変更を実行できる自律型エージェントを構築またはデプロイしたい開発者向けに設計されています。
ユーザーは、stdioトランスポートを使用して、Claude CodeやHermesなどのMCP互換のハーネスにサーバーを接続します。プライベートリーグにアクセスするには、ESPNのリーグID、チームID、およびespn_s2やSWIDを含む特定のブラウザクッキーが必要です。サーバーは約25個のツールを提供しており、リアルタイムドラフト用のget_draft_contextや、毎週のロースター管理用のset_lineupなどが含まれます。エージェントが変更を即座に適用できるか、あるいはrequest_approvalツールを使用してモバイル通知経由で許可を求める必要があるかを構成することで、自律性のレベルを制御できます。
できること
- 1ドラフト管理の自動化エージェントがライブ指名を追跡し、ドラフト中にVORP(Value Over Replacement Player)に基づいた選手の推奨事項を提供できます。
- 2毎週のラインナップ最適化エージェントがキックオフ前に、毎週の予測に基づいてスターティングロースターを自動的に調整できます。
- 3ウェイバーおよびフリーエージェンシーAIがロースターに追加すべき最適な選手を特定し、どの選手をリリースすべきかを提案できます。
- 4トレードのスカウティングと交渉サーバーを通じてエージェントがリーグ内をスキャンし、潜在的なトレード相手を見つけたり、提案された取引の影響を分析したりできます。
プロジェクトの README から作成されています。すべてのユースケースは、その引用と照らし合わせて確認されています。
Dodi MCPツール 26
READMEから検出get_draft_contextnext_pickget_draft_stateget_available_playersget_value_boardget_playerrefresh_draft_orderrefresh_boardget_matchupset_lineupmove_playerget_roster
| get_draft_context | — | |
| next_pick | — | |
| get_draft_state | — | |
| get_available_players | — | |
| get_value_board | — | |
| get_player | — | |
| refresh_draft_order | — | |
| refresh_board | — | |
| get_matchup | — | |
| set_lineup | — | |
| move_player | — | |
| get_roster | — |
26個のツールをすべて表示ツールを折りたたむ
notify_managerget_waiver_targetsadd_playerdrop_playerfind_trade_partnersanalyze_tradepropose_tradeget_pending_tradesrespond_to_tradeget_league_settingsget_transactionsrequest_approvalget_proposalscheck_report
| notify_manager | — | |
| get_waiver_targets | — | |
| add_player | — | |
| drop_player | — | |
| find_trade_partners | — | |
| analyze_trade | — | |
| propose_trade | — | |
| get_pending_trades | — | |
| respond_to_trade | — | |
| get_league_settings | — | |
| get_transactions | — | |
| request_approval | — | |
| get_proposals | — | |
| check_report | — |
自動チェック
実行日 2026年11月14日完全なレポート →まだ検証されていません。サーバーには80点のスコア、重大な問題がないこと、および検証に必要な十分なデータが必要です。 チェックの仕組み · 点数を上げるための改善点
- ソースリポジトリがリンクされており、アクセス可能hamcops/dodi is public and reachablegithub.com/hamcops/dodi ↗合格
- パッケージがこのリポジトリをソースとして指定未チェック
- ビルドの来歴 (Sigstore 証明)未チェック
- オープンソースライセンス (OSI)MITspdx.org/licenses/MIT.html ↗合格
- 過去1年以内にコミットまたはリリースありLast commit or release 2026-11-07github.com/hamcops/dodi ↗合格
- OpenSSF Scorecard未チェック
- パッケージ名が有名なパッケージに酷似していない未チェック
- パッケージおよびその依存関係に重大な勧告なし未チェック
- モデルへの隠れた指示がない26 tool descriptions and the README read; no override phrases, credential paths or hidden characters合格
- 破壊的なツールがラベル付けされている未チェック
- リモートエンドポイントが MCP ハンドシェイクに応答未チェック
README
GitHubで見るD.O.D.I. Draft Optimization Dynasty Intelligence
An MCP server that gives your AI agent full control of an ESPN fantasy football league — draft picks, weekly lineups, waivers, trades, and roster moves. Wire it into any MCP-compatible harness (Claude Code, Hermes, your own), give the agent a persona and a cron schedule, and let it run your season.
We call ours Dodi — Draft Optimization & Dynasty Intelligence. Dodi checks the waiver wire every afternoon, optimizes the lineup before kickoff, scouts trade partners, fires off offers, responds to incoming trades, and pings us on the phone when something happens. Dodi doesn't ask permission to set the best lineup. Dodi does ask before trading away your RB1. You decide where that line is.
What this is for
You have an AI agent (LLM + tool loop). You want it to manage an ESPN fantasy football team — not answer trivia about one, but actually read the league state, do the math, and submit roster changes. This server is the tool layer. It handles:
- The draft. Live pick tracking, VORP-ranked boards, on-the-clock recommendations, and optional browser automation to click DRAFT for you.
- Weekly lineups. Start/sit optimization against ESPN's weekly projections, with one call to preview and one to apply.
- Waivers and free agents. Every unrostered player scored by what he does to your starting lineup, with drop candidates ranked by expendability.
- Trades. League-wide partner scouting, both-sides-win analysis, proposal submission, and inbox management.
- Transactions. Full league history — who moved whom, when — so your agent can detect when opponents are active or asleep.
The server never guesses. Every writing tool previews the exact change by
default and only submits with apply=true. Where you draw the autonomy line —
auto-apply lineups, require confirmation for trades, let it YOLO everything —
is up to your agent's prompt.
Quick start
python3 -m venv .venv
./.venv/bin/pip install -e ".[dev]"
cp .env.example .env # fill in your credentials (see below)
./.venv/bin/python scripts/doctor.py # validates creds, prints league info + top-10 board
Register with your harness
Claude Code / Hermes:
claude mcp add espn-fantasy -- "$(pwd)/.venv/bin/python" -m espn_mcp.server
Generic MCP (stdio transport):
{
"command": "/path/to/espn-mcp/.venv/bin/python",
"args": ["-m", "espn_mcp.server"],
"transport": "stdio"
}
The server exposes ~25 tools. Your agent discovers them via MCP's tools/list.
No tool configuration needed on the harness side.
Credentials
ESPN_LEAGUE_ID — the number in fantasy.espn.com/football/league?leagueId=...
ESPN_TEAM_ID — the teamId= in your roster page URL.
Private leagues (most are) also need two cookies from a browser session logged
into ESPN. DevTools → Application → Cookies → fantasy.espn.com:
espn_s2— long URL-encoded string, full valueSWID— UUID with the braces:{F64EC866-...}
Put all four in .env. The file is gitignored. These are session credentials —
treat them like a password. They're scoped to .espn.com over HTTPS and never
sent elsewhere. They expire mid-season; an auth error means re-copy them.
Tools
Draft
| Tool | What it does |
|---|---|
get_draft_context |
The on-the-clock call. Board state, roster needs, VORP-ranked candidates, tier depth, position runs, picks until your next turn. One round-trip. |
next_pick |
Same decision in ~1KB — candidates that fill a hole, tier cliffs, time pressure. |
get_draft_state |
Picks made, who's on the clock, your upcoming slots. Never cached. |
get_available_players |
Undrafted pool by VORP, projection, or ADP. |
get_value_board |
Replacement levels and tier structure — the math behind the rankings. |
get_player |
One player in detail: projection, VORP, tier, ADP, injury. |
record_picks / record_pick |
Enter picks by name as they happen. Persisted to state/. |
undo_pick / reset_draft |
Fix mistakes or start fresh. |
refresh_draft_order |
Re-read after a randomized draw. |
refresh_board |
Force pool re-fetch after breaking news. |
Weekly lineup
| Tool | What it does |
|---|---|
get_matchup |
Both lineups, start/sit swaps with point values, opponent holes, win probability. week=N for lookahead. |
set_lineup |
Preview the optimal swaps; apply=true submits them. Locked players (game started) are planned around. |
move_player |
One player → one slot. Swaps out the weakest occupant if the slot is full. Under approvals it refuses a move that lowers this week's projection. |
get_roster |
Any team's full roster with projections and positional strength. |
notify_manager |
A short push saying a report is waiting, so an agent needs no shell to ping. Title 60 chars, message 200, no links. |
Waivers and free agents
| Tool | What it does |
|---|---|
get_waiver_targets |
Best pickups by lineup impact (ROS and this-week), drop candidates, waiver timing. |
add_player |
Free-agent add (instant) or waiver claim (queued), with optional drop in the same transaction. |
drop_player |
Cut a player. Preview shows what the lineup loses. |
Trades
| Tool | What it does |
|---|---|
find_trade_partners |
League-wide scan: who's weak where you're strong, mutual-fit candidates, trade blocks, records. |
analyze_trade |
Both sides before/after: starter strength, bench value, roster legality. |
propose_trade |
Preview or send (apply=true) an offer to another manager. |
get_pending_trades |
Inbox: offers waiting on you and offers you sent. |
respond_to_trade |
Accept, decline, or withdraw. |
League info
| Tool | What it does |
|---|---|
get_league_settings |
Scoring, roster slots, team count, draft type. Call once per session. |
get_transactions |
Full transaction log — lineup moves, adds, drops, claims, trades — by team and week. |
Approvals
| Tool | What it does |
|---|---|
request_approval |
Queue an add, drop, trade offer, trade answer or start/sit call for the manager. Previewed first; sent to ESPN only when approved. |
get_proposals |
What is waiting, and what was approved, rejected or expired. |
check_report |
Is every number in this report one a tool returned in the last 45 minutes? For the agent to run on its own report before delivering it. |
Running it hands-off
Everything in this section is optional and off by default. Each part is
switched on in .env; .env.example documents the settings.
Approve from your phone
With ESPN_REQUIRE_APPROVAL=1, roster moves and trades can no longer be
sent directly: add_player, drop_player, propose_trade and
respond_to_trade refuse apply=true, in the server, whatever the prompt
says. The agent queues them with request_approval, and you get an
ntfy notification with Approve, Reject and Details
buttons. Lineup changes stay direct.
espn-mcp-approve is the service behind the buttons. It listens on
loopback only. Put it behind something private (a tailnet, a VPN), never
the open internet: approving a proposal makes a real roster move. Each
proposal has its own token, a decision can be made once, and a proposal
interrupted mid-send is closed, never retried.
What the agent writes is checked
The numbers behind a move are computed in code. The sentence explaining it is written by a language model, which will now and then write a number that is close to the right one or belongs to another player. So:
request_approvalrefuses reasoning that quotes a number not in the move's own preview, and says which.check_reportdoes the same for a whole report, against every number the tools have returned lately.- The notification labels its two parts: THE MOVE, built by the server from ESPN's data, and the agent's view, in the agent's words.
espn-mcp-factsprints what is true right now (the week, who is locked, open trades, the queue) for a scheduler to put in front of the agent's prompt, so that it is copied and not recalled.
Only numbers can be checked this way. A right number on the wrong player, or sound numbers and a poor conclusion, still get through.
Decisions by the kickoff clock
Run espn-mcp-tick every five minutes. For each group of games on your
roster it counts back from the real kickoff:
| When | What |
|---|---|
| Kickoff − 65 min | Calls GAMETIME_HOOK, to start your agent |
| Kickoff − 45 min | Sets the lineup (espn-mcp-lineup, no model) and sends close calls |
| Kickoff − 5 min | Approval requests for that game expire |
Both runs come after inactives are announced, and leave
APPROVAL_LEAD_MINUTES (default 30) to answer. espn-mcp-tick status
prints the week's plan.
Once a week there is a third run. By Monday night every player on a roster
has played and is locked, so nobody can be dropped and no pickup made, until
ESPN rolls over to the new week. The scheduler watches for that and calls
the hook with roster the first time it sees it between 9 AM and 9 PM, so
claims reach you as early as they can be made.
The hook is called as <hook> <agent|roster> <weekday> <kickoff> and should
start the agent and return at once, not wait for it.
Outside data
With ESPN_EXTERNAL_SOURCES=1, player records also carry:
| Field | Source | What it is |
|---|---|---|
market |
FantasyCalc | Trade value from completed trades |
usage |
nflverse | Points scored against what carries and targets say he should score |
game |
ESPN scoreboard, Open-Meteo | Betting line, roof, forecast at kickoff |
adj_week_proj |
derived | ESPN's projection moved by the betting line; the lineup is set by it |
adds_24h, alt_week_proj, injury_alt |
Sleeper | Pickup trend, a second projection, a second injury report |
All public, no keys. Every source is cached and fails soft: one that is down leaves its fields off and the tools carry on with ESPN alone.
What is used and how much it counts was decided by testing each signal on
two past seasons, fit on one and scored on the other. Most did not survive.
research/README.md has the method, the results,
what was thrown out, and the scripts to rerun it.
ESPN's analysts
ESPN's own analysts publish weekly position ranks, and the player pool
returns them on the same request (no extra call, no outside source). Player
records carry expert: the rank at the position this week, how many
analysts it comes from, and, in a standard league, the spread across the
PPR panel. get_matchup and set_lineup add experts: where the lineup
their ranks would set differs from the one set.
Measured for 2026 week 4: eight analysts publish PPR ranks and one publishes standard ranks, and the two lists differ for 119 of 271 players. In a standard league the expert rank is therefore one analyst's. ESPN identifies analysts by number only; no mapping to names is claimed. Unpublished rows (about 40%) are dropped. The lineup is never set by the experts: they are scored against it in the weekly review.
Weekly review
espn-mcp-report prints last week's result, the points left on the bench,
what starting by ESPN's analysts' ranks would have scored,
how each projection did against what was recorded before kickoff, and how
the approved and rejected moves turned out.
Building an agent on top (the Dodi pattern)
The MCP server is the tool layer. Your agent is the brain. Here's how Dodi works as a reference architecture:
1. Write a system prompt
Give the agent a persona, decision framework, and autonomy rules. Dodi's:
- Aggressive, data-driven, no sentimentality
- Auto-applies lineup optimizations (no confirmation needed)
- Reports trade recommendations but waits for approval (or not — your call)
- Returns
[SILENT]when there's nothing to report, so the harness skips delivery
2. Schedule recurring runs
Dodi runs as four cron jobs in Hermes, each loading the same skill/prompt:
| Schedule | Purpose |
|---|---|
| Sunday 01:00 UTC | Full pre-game: matchup analysis, lineup optimization, trade scan, waiver check |
| Thursday 01:00 UTC | TNF lineup lock — make sure Thursday starters are set |
| Tue–Sat 20:00 UTC | Daily trade inbox + waiver wire scan |
| Monday 22:00 UTC | MNF late injury check |
Each run delivers a report to Discord and a short push notification to the
phone via ntfy (the notify_manager tool), so you know to check it without
staring at Discord all day.
Give the agent the MCP server and nothing else. Team names are written by
the other managers and reach the prompt; the server strips them to short,
plain labels, but an agent with a shell could still be talked into reading
.env or the approval queue. In Hermes, set the job's enabled_toolsets to
just this server (e.g. ["espn"]).
3. Let it write
The tools default to apply=false (preview only). Your prompt decides when
the agent calls with apply=true. Dodi auto-applies set_lineup but previews
trades. A more aggressive agent could auto-send trades where both sides gain.
A cautious one could preview everything. The server doesn't care — it enforces
the preview/apply split, your prompt enforces policy.
How it decides
VORP, not projected points. Raw projections say draft a QB first — the top QB outscores the top RB. That's wrong in a 1-QB league because the 12th QB also scores a lot, making the top QB's edge over replacement small. VORP measures each player against the last startable player at his position in your league: team count, starting slots, and an empirical FLEX allocation. Scoring rules (PPR, half-PPR, TE premium, custom) are read from the league — no configuration needed.
Two projections in season. week_proj is ESPN's weekly number (reflects
opponent, injury, bye) — decides start/sit. ros_pg is rest-of-season points
per remaining game — decides roster value, trade worth, waiver priority.
Everything is a change to the optimal starting lineup. A pickup who sits behind what you have gains 0 whatever his projection. A trade is judged by what each side's starters project before and after. The lineup solver runs the same way for every team, so strength is comparable league-wide.
Tiers are 1-D k-means over each position's draftable range. "Players left in this tier" adapts to the local distribution instead of panicking at every gap.
Draft day
ESPN publishes no picks until a draft ends — verified against real drafts. The read API reports zero picks and empty rosters while the room is live, then everything at once on completion. Your agent needs picks fed in as they happen:
record_picks(["Gibbs", "Chase", ...])each turn, only the new names. Persisted tostate/, survives restarts, deduplicates on re-send.- Or use the browser scripts:
live_draft.pywatches the room and records automatically,sync_from_room.pyseeds from room history if you join late,draft_player.pyclicks DRAFT, andautodraft.pyruns the whole draft on the value board. These needpip install -e ".[browser]"and Chrome with--remote-debugging-port=9222(bind to 127.0.0.1, close after). snapshot.pysaves the full board tosnapshots/as JSON and CSV before the draft, so an ESPN outage doesn't leave you blind.
On the clock, get_draft_context returns picks_between_this_and_next — the
number that decides if a player will last. ADP entries include adp_moving
("earlier" / "later") and adp_age_hours so your agent can discount stale
market data.
ESPN quirks handled
Each found against a real league, each with a regression test.
- Placeholder picks and negative IDs. Unstarted drafts pre-seed every slot
with
playerId: -1. D/ST IDs are also negative. Exact-1match, not> 0filtering. - No D/ST projections. Defenses project 0.0; they're marked
ranked_by: espn_adpwithvorp: nulland sort below real-value players. - Non-contiguous team IDs. A 10-team league can have IDs
[1,2,3,6,7,8,9,10,12,13]. Draft slot comes from position in the order. - Weekly stats require per-week requests. One
scoringPeriodIdper fetch. - Mid-week scores use
*Livefields.totalPointsstays 0 until the week is final;totalPointsLivehas the running score. - Draft time is epoch ms in UTC. Rendered in local time with countdown.
- Randomized draft order rewrites late. Read from ESPN's pick schedule
(live, uncached), not settings.
draft_slot_is_provisionalflags pre-draw.
Cookie expiry, datacenter IP blocks, and ESPN's mediocre projections are the other failure modes. The value math and ADP-vs-value gaps are the edge — ESPN's ADP reflects what your ESPN leaguemates will actually do.
Caching
Player pool: ESPN_POOL_TTL seconds (default 900). Rosters: 60s, refreshed
after writes. Draft state and transaction log: never cached.
Tests
./.venv/bin/python -m pytest tests/ -q
118 tests, no network, no credentials. ESPN client stubbed with real payloads. Covers value math, snake ordering, board assembly, lineup solving, trade/waiver arithmetic, every write's transaction shape, and cookie scoping.
Layout
src/espn_mcp/
config.py .env loading, secret masking
espn.py HTTP client: host pin, cookie scoping, reads and writes
constants.py ESPN position / slot / pro-team ID maps
scoring.py league shape parsing, league-scored projections
value.py replacement level, VORP, tiers (pure, tested)
season.py ROS, optimal lineups, lineup plans,
trade / waiver deltas, transaction log (pure, tested)
board.py caching layer, draft state, in-season rosters and matchups
server.py the MCP tools
proposals.py the approval queue (pure, tested)
notify.py ntfy pushes and the approval buttons
approve.py the service behind the buttons
gametime.py scheduling counted back from kickoff
autolineup.py set the lineup without a model
usage.py expected points from workload (pure, tested)
factcheck.py numbers in the agent's text against the tools' (pure, tested)
market.py trade arithmetic on market values (pure, tested)
tracking.py what was known before kickoff, for scoring later
experts.py ESPN analysts' weekly ranks, and where they disagree
report.py the weekly review
sources/ Sleeper, FantasyCalc, nflverse, betting lines, weather
research/ the backtests behind every outside signal
scripts/
doctor.py credential + access check
snapshot.py offline fallback board
live_draft.py watch the draft room, record picks (browser)
sync_from_room.py seed board from room history (browser)
draft_player.py click DRAFT in the room (browser)
autodraft.py draft on the value board (browser)
watch_draft.py poll read API during draft (proves it lags)
simulate_draft.py offline mock draft
simulate_autodraft.py offline autodraft scorer
grade_external.py grade rosters against outside ranking
state/ picks, browser profile, notes (gitignored)
Dodi MCPのよくある質問
Dodi MCPが提供するツールは
26個のツールを提供しており、get_draft_context, next_pick, get_draft_state, get_available_players, get_value_boardなどがあります。
Dodiサーバーを使うと、リーグ内で具体的に何ができますか?
ドラフト指名、毎週のラインナップ、ウェイバー、トレード、ロースターの変更など、リーグ全体を完全にコントロールできます。
選手のトレードのような機密性の高いアクションはどのように処理されますか?
自律性の境界を設定できます。例えば、主力選手のトレードなど特定の操作に対して、エージェントがユーザーの承認を必要とするように設定可能です。
モバイルデバイスからロースターの変更を承認できますか?
はい、特定のプロパティを有効にすることで、サーバーがスマートフォンに通知を送信し、ボタン操作で提案を承認または拒否できるようになります。