# v12-dfs MCP server

AI-driven DFS lineup optimizer for MLB & NBA — build FanDuel & DraftKings lineups via MCP.

## Links
- Registry page: https://www.getdrio.com/mcp/io-github-jorgeperez0825-v12-dfs

## Install
- Endpoint: https://v12dfs-production.up.railway.app/mcp
- Auth: Auth required by registry metadata

## Setup notes
- Remote header: X-API-Key (required; secret)
- The upstream registry signals required auth or secrets.
- Remote endpoint: https://v12dfs-production.up.railway.app/mcp
- Header: X-API-Key

## Tools
- agent_guide - Agent Guide

Self-serve onboarding: connect any agent (Claude/MCP or REST) to drive the
V12 motor, the same engine the dashboard agent uses. No auth. Returns
copy-paste MCP + REST config with a PLACEHOLDER key, the endpoint map, and the
generate body fields. Operators: issue each user their OWN key via
POST /v1/admin/create-key — never share one key.

### Responses:

**200**: Successful Response (Success Response)
Content-Type: application/json Endpoint: https://v12dfs-production.up.railway.app/mcp
- health_check - Health

### Responses:

**200**: Successful Response (Success Response)
Content-Type: application/json

**Example Response:**
```json
{
  "status": "Status",
  "version": "Version",
  "timestamp": "Timestamp"
}
``` Endpoint: https://v12dfs-production.up.railway.app/mcp
- health_v12 - Health V12

Deep health check for the V12 pipeline. Surfaces:
  - last nightly regression run (pass/fail + per-slate deltas)
  - regression baseline metadata
  - recent preflight blockers (if any cached)
No auth required — monitoring endpoint.

### Responses:

**200**: Successful Response (Success Response)
Content-Type: application/json Endpoint: https://v12dfs-production.up.railway.app/mcp
- list_slates - Get Slates

List available V12 slates for today. Returns slate IDs, game counts, and lock times.

### Responses:

**200**: Successful Response (Success Response)
Content-Type: application/json
**422**: Validation Error
Content-Type: application/json

**Example Response:**
```json
{
  "detail": [
    {
      "loc": [],
      "msg": "Message",
      "type": "Error Type",
      "ctx": {}
    }
  ]
}
``` Endpoint: https://v12dfs-production.up.railway.app/mcp
- get_slate_players - Get Slate Players Endpoint

Get the V12 player pool for a specific slate ID.

### Responses:

**200**: Successful Response (Success Response)
Content-Type: application/json
**422**: Validation Error
Content-Type: application/json

**Example Response:**
```json
{
  "detail": [
    {
      "loc": [],
      "msg": "Message",
      "type": "Error Type",
      "ctx": {}
    }
  ]
}
``` Endpoint: https://v12dfs-production.up.railway.app/mcp
- slate_health - Slate Health

Pre-flight diagnostic for a slate. Returns whether odds, projections,
matchup, and FD master-session are ready BEFORE the agent invokes
/v1/generate.

Either slate_id or date is required. When slate_id is given, the slate
metadata is also returned (games list, lock times). When only date is
given, the data-pillar checks still run but game coverage cannot be
computed (returned as null).

READING THE PROJECTION FRESHNESS (MLB especially): `stokastic.age_min` is the
age of the cached snapshot FILE, NOT a data-quality signal. For MLB the cache
is refreshed only twice a day, so mid-afternoon it routinely reads several
hours old AND THAT IS FINE — a user-facing generate fetches projections LIVE
(refresh_data=true), and `stokastic.generate_fetches_live=true` flags this.
A stale `age_min` with a loaded, populated pool is NOT "projections broken /
aces at 0 / no edge": probable pitchers are set days ahead (non-zero), and
only confirmed BATTING lineups firm up ~1-2h before lock. Do NOT treat a stale
cache age as a blocker or tell the user to wait/re-refresh — check the actual
pool (get_slate_players) for non-zero pitcher projections instead.

### Responses:

**200**: Successful Response (Success Response)
Content-Type: application/json
**422**: Validation Error
Content-Type: application/json

**Example Response:**
```json
{
  "detail": [
    {
      "loc": [],
      "msg": "Message",
      "type": "Error Type",
      "ctx": {}
    }
  ]
}
``` Endpoint: https://v12dfs-production.up.railway.app/mcp
- slate_refresh - Slate Refresh

Re-fetch projections + odds + slate metadata for a date.

Writes to the configured store (Supabase in prod). Returns a summary
dict (date, slate_id, n_games, n_players, n_upserted, n_odds, backend).

Auth: requires X-API-Key OR X-Internal-Secret (cron use). This is a
write op that costs one Stokastic + one ESPN API call.

### Responses:

**200**: Successful Response (Success Response)
Content-Type: application/json
**422**: Validation Error
Content-Type: application/json

**Example Response:**
```json
{
  "detail": [
    {
      "loc": [],
      "msg": "Message",
      "type": "Error Type",
      "ctx": {}
    }
  ]
}
``` Endpoint: https://v12dfs-production.up.railway.app/mcp
- slate_diff - Slate Diff

Compute what changed since a previously-stored snapshot.

Body shape:
  {
    "slate_id": 32867,
    "date": "2026-05-11",
    "sport": "NBA",
    "site": "FD",
    "previous": {
      "v": "v1",
      "players": [{"id","name","status","salary","proj"}, ...],
      "odds":    [{"game","ou","spread","home_ml","away_ml"}, ...]
    }
  }

Returns a structured diff: which players changed status / salary /
projection, which games moved spread or O/U, which players were added
or removed from the pool. The thresholds for "changed":
  - status: any non-empty difference (Q→OUT, ''→OUT, GTD→IN, etc.)
  - salary: any integer delta
  - projection: |delta| >= 0.5 fantasy points
  - odds spread: |delta| >= 0.5
  - odds ou: |delta| >= 0.5
  - odds ml: |delta| >= 10 (American odds noise floor)

No auth required — read-only computation off in-memory current snapshot
plus the caller-supplied previous one.

### Responses:

**200**: Successful Response (Success Response)
Content-Type: application/json
**422**: Validation Error
Content-Type: application/json

**Example Response:**
```json
{
  "detail": [
    {
      "loc": [],
      "msg": "Message",
      "type": "Error Type",
      "ctx": {}
    }
  ]
}
``` Endpoint: https://v12dfs-production.up.railway.app/mcp
- list_presets - Get Presets

List the available strategy presets (gpp_pro_pattern, gpp_sniper, gpp_balanced, gpp_volume, cash_grinder, gpp_contrarian, gpp_mass_entry) with their configurations. No auth required.

### Responses:

**200**: Successful Response (Success Response)
Content-Type: application/json
**422**: Validation Error
Content-Type: application/json

**Example Response:**
```json
{
  "detail": [
    {
      "loc": [],
      "msg": "Message",
      "type": "Error Type",
      "ctx": {}
    }
  ]
}
``` Endpoint: https://v12dfs-production.up.railway.app/mcp
- generate_lineups - Generate Lineups

### Responses:

**200**: Successful Response (Success Response)
Content-Type: application/json

**Example Response:**
```json
{
  "status": "Status",
  "generated_at": "Generated At",
  "warnings": [],
  "exposures": {},
  "lineups": []
}
```
**422**: Validation Error
Content-Type: application/json

**Example Response:**
```json
{
  "detail": [
    {
      "loc": [],
      "msg": "Message",
      "type": "Error Type",
      "ctx": {}
    }
  ]
}
``` Endpoint: https://v12dfs-production.up.railway.app/mcp
- run_mlb_postmortem - Run Mlb Postmortem

### Responses:

**200**: Successful Response (Success Response)
Content-Type: application/json

**Example Response:**
```json
{
  "status": "Status",
  "generated_at": "Generated At",
  "date": "Date",
  "game_id": "Game Id",
  "entries": 1,
  "field_lineups": 1,
  "training_rows": 1,
  "missing_sources": [
    "string"
  ],
  "results": {},
  "history_validation": {},
  "field": {},
  "diagnostics": {},
  "simulator_feed": {},
  "warnings": [
    "string"
  ]
}
```
**422**: Validation Error
Content-Type: application/json

**Example Response:**
```json
{
  "detail": [
    {
      "loc": [],
      "msg": "Message",
      "type": "Error Type",
      "ctx": {}
    }
  ]
}
``` Endpoint: https://v12dfs-production.up.railway.app/mcp
- list_contests - Contest Registry

List contest strategy registry entries for agents and the dashboard.

### Responses:

**200**: Successful Response (Success Response)
Content-Type: application/json
**422**: Validation Error
Content-Type: application/json

**Example Response:**
```json
{
  "detail": [
    {
      "loc": [],
      "msg": "Message",
      "type": "Error Type",
      "ctx": {}
    }
  ]
}
``` Endpoint: https://v12dfs-production.up.railway.app/mcp
- list_live_contests - Live Contests

Return latest V12 contest context without backend identifiers.

### Responses:

**200**: Successful Response (Success Response)
Content-Type: application/json
**422**: Validation Error
Content-Type: application/json

**Example Response:**
```json
{
  "detail": [
    {
      "loc": [],
      "msg": "Message",
      "type": "Error Type",
      "ctx": {}
    }
  ]
}
``` Endpoint: https://v12dfs-production.up.railway.app/mcp
- contest_advice - Contest Advice

Advice for a concrete contest name. Resolves the name against the LIVE
lobby FIRST so a real live contest is never reported missing (the curated
registry is only a subset — that was the "$800 Wed MLB Home Run no existe"
bug), then layers registry strategy advice on top when a template matches.

### Responses:

**200**: Successful Response (Success Response)
Content-Type: application/json
**422**: Validation Error
Content-Type: application/json

**Example Response:**
```json
{
  "detail": [
    {
      "loc": [],
      "msg": "Message",
      "type": "Error Type",
      "ctx": {}
    }
  ]
}
``` Endpoint: https://v12dfs-production.up.railway.app/mcp
- fill_template - Fill Template

Fill a downloaded FanDuel/DK entries-template with already-generated
lineups WITHOUT re-running the optimizer — the MCP-callable equivalent of the
dashboard's fill_template. Keeps each entry row's leading columns (entry_id,
contest_id, fee) and replaces the roster-slot columns with a lineup's upload
tokens, cycling lineups if there are more entry rows than lineups.

### Responses:

**200**: Successful Response (Success Response)
Content-Type: application/json
**422**: Validation Error
Content-Type: application/json

**Example Response:**
```json
{
  "detail": [
    {
      "loc": [],
      "msg": "Message",
      "type": "Error Type",
      "ctx": {}
    }
  ]
}
``` Endpoint: https://v12dfs-production.up.railway.app/mcp
- admin_issue_key - Issue Key

Idempotently issue a user's API key and ALWAYS return the paste-able
connect block. Returns the email's existing active key (or mints one) so a
user keeps a single key across dashboard reloads; with rotate=true, revokes
the existing keys and mints a fresh one. Admin-gated — the dashboard's
per-user provision route (which verifies the user's Firebase token) calls
this server-side, never the browser.

### Responses:

**200**: Successful Response (Success Response)
Content-Type: application/json

**Example Response:**
```json
{
  "api_key": "Api Key",
  "tier": "Tier",
  "limits": {}
}
```
**422**: Validation Error
Content-Type: application/json

**Example Response:**
```json
{
  "detail": [
    {
      "loc": [],
      "msg": "Message",
      "type": "Error Type",
      "ctx": {}
    }
  ]
}
``` Endpoint: https://v12dfs-production.up.railway.app/mcp
- betting_agent_guide - Betting Agent Guide

How any agent uses the MLB betting tools + how to read the output.

### Responses:

**200**: Successful Response (Success Response)
Content-Type: application/json Endpoint: https://v12dfs-production.up.railway.app/mcp
- betting_player_form - Player Form

Streak / splits / recent form for any player ('racha de X').

### Responses:

**200**: Successful Response (Success Response)
Content-Type: application/json
**422**: Validation Error
Content-Type: application/json

**Example Response:**
```json
{
  "detail": [
    {
      "loc": [],
      "msg": "Message",
      "type": "Error Type",
      "ctx": {}
    }
  ]
}
``` Endpoint: https://v12dfs-production.up.railway.app/mcp
- betting_analyze_prop - Analyze Prop

Model a single player's prop vs tonight's FanDuel line -> edge.

### Responses:

**200**: Successful Response (Success Response)
Content-Type: application/json
**422**: Validation Error
Content-Type: application/json

**Example Response:**
```json
{
  "detail": [
    {
      "loc": [],
      "msg": "Message",
      "type": "Error Type",
      "ctx": {}
    }
  ]
}
``` Endpoint: https://v12dfs-production.up.railway.app/mcp
- betting_scan_edges - Scan Edges

Tonight's prop board ranked by model edge (VALUE first).

### Responses:

**200**: Successful Response (Success Response)
Content-Type: application/json
**422**: Validation Error
Content-Type: application/json

**Example Response:**
```json
{
  "detail": [
    {
      "loc": [],
      "msg": "Message",
      "type": "Error Type",
      "ctx": {}
    }
  ]
}
``` Endpoint: https://v12dfs-production.up.railway.app/mcp
- betting_best_bets - Best Bets

THE board sweep — scans EVERY main prop market (HR/RBI/hit/total_bases/
2+hits/stolen_base) in one call and returns the top edges across all of them,
not just home runs. Power props carry the Savant validation (CONFIRMED power
ranked above neutral/noise). Use this for an open 'what's hot / best plays /
what do you recommend tonight' so you NEVER conclude off a single-market scan.
A SCREEN vs the vig line — validate with CLV; game-side value is separate
(betting_sharp / betting_game_model).

### Responses:

**200**: Successful Response (Success Response)
Content-Type: application/json
**422**: Validation Error
Content-Type: application/json

**Example Response:**
```json
{
  "detail": [
    {
      "loc": [],
      "msg": "Message",
      "type": "Error Type",
      "ctx": {}
    }
  ]
}
``` Endpoint: https://v12dfs-production.up.railway.app/mcp
- betting_build_parlay - Build Parlay

Correlation-aware analysis of a parlay (>=2 prop legs). Body:
{legs:[{name, prop, threshold}]}. Returns naive vs correlation-adjusted EV,
Kelly stake, and the honest verdict — the parlay-specific edge is the
correlation lift on same-game legs; cross-game parlays are -EV by the vig.

### Responses:

**200**: Successful Response (Success Response)
Content-Type: application/json
**422**: Validation Error
Content-Type: application/json

**Example Response:**
```json
{
  "detail": [
    {
      "loc": [],
      "msg": "Message",
      "type": "Error Type",
      "ctx": {}
    }
  ]
}
``` Endpoint: https://v12dfs-production.up.railway.app/mcp
- betting_log_bet - Log Bet

Record a bet you placed (per user) so we can track P&L + CLV over time.
Body: {uid, market, selection, odds (American), stake, line?, prop?, team?,
game?, book?}. Append-only — this is the evidence base that PROVES edge.

### Responses:

**200**: Successful Response (Success Response)
Content-Type: application/json
**422**: Validation Error
Content-Type: application/json

**Example Response:**
```json
{
  "detail": [
    {
      "loc": [],
      "msg": "Message",
      "type": "Error Type",
      "ctx": {}
    }
  ]
}
``` Endpoint: https://v12dfs-production.up.railway.app/mcp
- betting_my_bets - My Bets

A user's bet history + P&L / CLV summary. avg_clv_pct > 0 over time = you're
beating the closing line = real edge (the only durable proof).

### Responses:

**200**: Successful Response (Success Response)
Content-Type: application/json
**422**: Validation Error
Content-Type: application/json

**Example Response:**
```json
{
  "detail": [
    {
      "loc": [],
      "msg": "Message",
      "type": "Error Type",
      "ctx": {}
    }
  ]
}
``` Endpoint: https://v12dfs-production.up.railway.app/mcp
- betting_settle_bet - Settle Bet

Settle a logged bet. Body: {uid, bet_id, result: won|lost|push,
closing_odds?}. closing_odds lets us compute CLV (did you beat the close).

### Responses:

**200**: Successful Response (Success Response)
Content-Type: application/json
**422**: Validation Error
Content-Type: application/json

**Example Response:**
```json
{
  "detail": [
    {
      "loc": [],
      "msg": "Message",
      "type": "Error Type",
      "ctx": {}
    }
  ]
}
``` Endpoint: https://v12dfs-production.up.railway.app/mcp
- betting_cross_book - Cross Book

Cross-book value: FanDuel vs DraftKings (DK pulled via ESPN's public API,
no key/WS). LINE_SHOP (the books hang different numbers — take the easier
side) and PRICE_SHOP (better price, same line) are CONFIRMED edges, no model
needed. Arbitrage is NOT auto-reported (needs over/under sides, which ESPN
doesn't label). Overnight only pitcher_strikeouts overlaps; richer markets
appear near game time.

### Responses:

**200**: Successful Response (Success Response)
Content-Type: application/json
**422**: Validation Error
Content-Type: application/json

**Example Response:**
```json
{
  "detail": [
    {
      "loc": [],
      "msg": "Message",
      "type": "Error Type",
      "ctx": {}
    }
  ]
}
``` Endpoint: https://v12dfs-production.up.railway.app/mcp
- betting_game_lines - Game Lines

GAME markets — moneyline / run total / run line for today's MLB games. This
answers the 'quién gana / cuántas carreras / pronóstico Yankees vs Toronto'
questions that player props CAN'T (V12 used to just refuse them). Optional
team filter ('Yankees', 'NYY'). MARKET data from ESPN's public scoreboard,
surfaced as-is — V12 has NO game-outcome model, so this is the book's own
number, never a fabricated prediction. A book may not have posted a game yet
(fields null) — say so, don't invent a line.

### Responses:

**200**: Successful Response (Success Response)
Content-Type: application/json
**422**: Validation Error
Content-Type: application/json

**Example Response:**
```json
{
  "detail": [
    {
      "loc": [],
      "msg": "Message",
      "type": "Error Type",
      "ctx": {}
    }
  ]
}
``` Endpoint: https://v12dfs-production.up.railway.app/mcp
- betting_market - Market

FULL FanDuel market board for a team's game — EVERY market with real odds +
de-vig fair price, so NO market question goes unanswered. Game lines (ML /
total / run line), FIRST 5 INNINGS (F5), TEAM TOTALS, NRFI/YRFI, alternate
lines, AND the full player-prop menu (HR / 2+ HR / hit / 2+ hits / RBI /
2+ RBI / run / single / double / triple / total bases / stolen base / K).
The book's market surfaced as-is (no model). For our model edge on a prop,
follow up with betting_analyze_prop.

### Responses:

**200**: Successful Response (Success Response)
Content-Type: application/json
**422**: Validation Error
Content-Type: application/json

**Example Response:**
```json
{
  "detail": [
    {
      "loc": [],
      "msg": "Message",
      "type": "Error Type",
      "ctx": {}
    }
  ]
}
``` Endpoint: https://v12dfs-production.up.railway.app/mcp
- betting_sharp - Sharp

SHARP value — FanDuel vs PINNACLE (the sharpest book, ~2% hold). Pinnacle's
de-vigged line ≈ TRUE probability, so this is the most reliable value signal in
the kit, NO model needed: edge_vs_sharp = FD's price minus the sharp's true
prob; POSITIVE means FanDuel pays MORE than fair (real value vs the market).
Plus total line-shop. Pinnacle only lists UPCOMING games (gone once started).

### Responses:

**200**: Successful Response (Success Response)
Content-Type: application/json
**422**: Validation Error
Content-Type: application/json

**Example Response:**
```json
{
  "detail": [
    {
      "loc": [],
      "msg": "Message",
      "type": "Error Type",
      "ctx": {}
    }
  ]
}
``` Endpoint: https://v12dfs-production.up.railway.app/mcp
- betting_game_model - Game Model

MODEL the GAME run markets — TEAM TOTALS (over/under) and NRFI/YRFI — vs the
FanDuel line, with an edge. A run model grounded in real inputs: each team's
season runs/game, the opposing STARTER + BULLPEN run factors, and the park
(team totals = negative-binomial since runs are over-dispersed; NRFI anchored
to the empirical ~0.53 base). A SCREEN vs the market, not a lock — validate
with CLV. For raw lines on every market use betting_market.

### Responses:

**200**: Successful Response (Success Response)
Content-Type: application/json
**422**: Validation Error
Content-Type: application/json

**Example Response:**
```json
{
  "detail": [
    {
      "loc": [],
      "msg": "Message",
      "type": "Error Type",
      "ctx": {}
    }
  ]
}
``` Endpoint: https://v12dfs-production.up.railway.app/mcp
- betting_matchup - Matchup

GROUNDING — the real game for a team today: probable pitchers + the POSTED
lineup (ACTUAL player names from MLB statsapi) + the market line + the CONTEXT
a pro reasons with: home-plate UMPIRE (strike zone → totals/Ks), the INJURY
report (who's OUT / Day-To-Day), and BULLPEN health (ERA / blown saves). Call
this BEFORE naming any player or discussing a game. Name ONLY the players this
returns — never a roster from memory (that is how the agent ends up naming
players who aren't on the team).

### Responses:

**200**: Successful Response (Success Response)
Content-Type: application/json
**422**: Validation Error
Content-Type: application/json

**Example Response:**
```json
{
  "detail": [
    {
      "loc": [],
      "msg": "Message",
      "type": "Error Type",
      "ctx": {}
    }
  ]
}
``` Endpoint: https://v12dfs-production.up.railway.app/mcp
- betting_market_movers - Market Movers

MARKET pattern (not model opinion): how FanDuel lines MOVED today, from the
captured snapshots. A line that shortened = money coming in (sharp/news); a
drift = money off. This is the 'obvious opportunity' signal — market-confirmed,
independent of our unproven model. Needs accumulated capture; thin → thin.

### Responses:

**200**: Successful Response (Success Response)
Content-Type: application/json
**422**: Validation Error
Content-Type: application/json

**Example Response:**
```json
{
  "detail": [
    {
      "loc": [],
      "msg": "Message",
      "type": "Error Type",
      "ctx": {}
    }
  ]
}
``` Endpoint: https://v12dfs-production.up.railway.app/mcp

## Resources
Not captured

## Prompts
Not captured

## Metadata
- Owner: io.github.Jorgeperez0825
- Version: 1.0.0
- Runtime: Streamable Http
- Transports: HTTP
- License: Not captured
- Language: Not captured
- Stars: Not captured
- Updated: Jun 17, 2026
- Source: https://registry.modelcontextprotocol.io
