v12-dfs
AI-driven DFS lineup optimizer for MLB & NBA — build FanDuel & DraftKings lineups via MCP.
사용해야 할까요
품질 및 안전성
발견 사항 (4)
- HIGH
- MEDIUMagent_guide에서
- LOWhealth_check에서
- INFOagent_guide에서
도구 정의와 프로토콜 준수에 대한 자동 분석을 기반으로 합니다.
컨텍스트 비용
이는 서버의 도구가 모델의 컨텍스트에 로드될 때마다 소비되는 대략적인 토큰 수입니다. 수치가 높을수록 다른 작업에 사용할 수 있는 주의가 줄어듭니다.
설치
원클릭 설치
`claude_desktop_config.json` 파일에 다음을 추가하세요:
{
"mcpServers": {
"v12-dfs": {
"url": "https://v12dfs-production.up.railway.app/mcp"
}
}
}원격 엔드포인트
https://v12dfs-production.up.railway.app/mcpstreamable-http할 수 있는 일
도구 목록
도구 (34)
🟡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
입력 스키마
{
"type": "object",
"properties": {},
"title": "agent_guideArguments"
}🟢health_check
Health ### Responses: **200**: Successful Response (Success Response) Content-Type: application/json **Example Response:** ```json { "status": "Status", "version": "Version", "timestamp": "Timestamp" } ```
입력 스키마
{
"type": "object",
"properties": {},
"title": "health_checkArguments"
}🟢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
입력 스키마
{
"type": "object",
"properties": {},
"title": "health_v12Arguments"
}🟢list_slates(site, sport, playable, compact, limit)
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": {} } ] } ```
입력 스키마
{
"type": "object",
"properties": {
"site": {
"type": "string",
"default": "fd",
"title": "site"
},
"sport": {
"type": "string",
"default": "NBA",
"title": "sport"
},
"playable": {
"type": "boolean",
"default": false,
"title": "playable"
},
"compact": {
"type": "boolean",
"default": false,
"title": "compact"
},
"limit": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"title": "limit",
"type": "integer"
}
},
"title": "list_slatesArguments"
}🟢get_slate_players(slate_id, compact, limit)
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": {} } ] } ```
입력 스키마
{
"type": "object",
"properties": {
"slate_id": {
"type": "integer",
"title": "slate_id"
},
"compact": {
"type": "boolean",
"default": false,
"title": "compact"
},
"limit": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"title": "limit",
"type": "integer"
}
},
"required": [
"slate_id"
],
"title": "get_slate_playersArguments"
}🟡slate_health(slate_id, date, site, sport, last_known_fingerprint, ...)
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": {} } ] } ```
입력 스키마
{
"type": "object",
"properties": {
"slate_id": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"title": "slate_id",
"type": "integer"
},
"date": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "date",
"type": "string"
},
"site": {
"type": "string",
"default": "fd",
"title": "site"
},
"sport": {
"type": "string",
"default": "NBA",
"title": "sport"
},
"last_known_fingerprint": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "last_known_fingerprint",
"type": "string"
},
"include_snapshot": {
"type": "boolean",
"default": false,
"title": "include_snapshot"
}
},
"title": "slate_healthArguments"
}🟡slate_refresh(date, sport, site)
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": {} } ] } ```
입력 스키마
{
"type": "object",
"properties": {
"date": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "date",
"type": "string"
},
"sport": {
"type": "string",
"default": "NBA",
"title": "sport"
},
"site": {
"type": "string",
"default": "FD",
"title": "site"
}
},
"title": "slate_refreshArguments"
}🟢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": {} } ] } ```
입력 스키마
{
"type": "object",
"properties": {},
"title": "slate_diffArguments"
}🟢list_presets(sport)
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": {} } ] } ```
입력 스키마
{
"type": "object",
"properties": {
"sport": {
"type": "string",
"default": "nba",
"title": "sport"
}
},
"title": "list_presetsArguments"
}⚪generate_lineups(date, sport, preset, platform, slate_id, ...)
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": {} } ] } ```
입력 스키마
{
"type": "object",
"properties": {
"date": {
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$",
"title": "date",
"description": "Slate date YYYY-MM-DD"
},
"sport": {
"anyOf": [
{
"type": "string",
"pattern": "^(nba|mlb|NBA|MLB)$"
},
{
"type": "null"
}
],
"title": "sport",
"description": "Sport engine to run: nba or mlb.",
"default": "nba",
"type": "string"
},
"preset": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "preset",
"description": "Strategy preset key.",
"default": "gpp_pro_pattern",
"type": "string"
},
"platform": {
"anyOf": [
{
"type": "string",
"pattern": "^(fd|dk|fanduel|draftkings)$"
},
{
"type": "null"
}
],
"title": "platform",
"description": "V12 platform profile: fd or dk.",
"default": "fd",
"type": "string"
},
"slate_id": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"title": "slate_id",
"description": "Specific slate ID from /v1/slates. Overrides date-based lookup.",
"type": "integer"
},
"contest_id": {
"anyOf": [
{
"type": "string",
"maxLength": 80
},
{
"type": "null"
}
],
"title": "contest_id",
"description": "Optional contest handle for building an entry-update CSV from the user's existing contest entries.",
"type": "string"
},
"entry_template_csv": {
"anyOf": [
{
"type": "string",
"maxLength": 4000000
},
{
"type": "null"
}
],
"title": "entry_template_csv",
"description": "Raw CSV of a FanDuel entries-upload-template the operator already downloaded. When present, the entry-upload is filled from its OWN entry_ids locally — no FanDuel API / session / PerimeterX call. Fixes fd_entry_template_auth_expired when the user already has the template in hand.",
"type": "string"
},
"contest_max_entries": {
"anyOf": [
{
"type": "integer",
"maximum": 150,
"minimum": 1
},
{
"type": "null"
}
],
"title": "contest_max_entries",
"description": "Max entries per user for the selected contest. Used to identify multi-entry mass GPPs (>=4) which keep the caller's preset. Field SIZE, not this, governs the MLB objective — see contest_field_size.",
"type": "integer"
},
"contest_field_size": {
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "null"
}
],
"title": "contest_field_size",
"description": "Total entries (field size) of the selected contest. Governs the MLB objective: field <= 10 -> max-mean (mlb_small_field_se); field > 10 -> ceiling (mlb_se_ceiling) with a continuous ceiling tilt and the real field size fed into contest simulation. A matched contest_id lobby row is authoritative; this value is the fallback when that row is unavailable.",
"type": "integer"
},
"contest_fallback": {
"anyOf": [
{
"type": "string",
"pattern": "^(slate_only)$"
},
{
"type": "null"
}
],
"title": "contest_fallback",
"description": "Escape hatch when a contest_id cannot be mapped to a slate (contest_slate_unresolved). 'slate_only' + an explicit slate_id builds on THAT slate and skips contest-specific behavior (field-size routing, entry-template mapping) instead of failing the whole generate. Requires slate_id; without it the request still fails closed. Omit for normal contest-anchored builds.",
"type": "string"
},
"plan_only": {
"type": "boolean",
"title": "plan_only",
"description": "When true, the server resolves preset / contest / authoritative slate / top-run-env / locks but does NOT run the optimizer. Returns a Plan response so the user can review and confirm before spending credits on a real generate. Costs 0 credits; normal slate-open safety checks still apply.",
"default": false
},
"fd_user_id": {
"anyOf": [
{
"type": "string",
"maxLength": 32,
"pattern": "^\\d+$"
},
{
"type": "null"
}
],
"title": "fd_user_id",
"description": "DEPRECATED on /v1/generate: fd_user_id is bound server-side to your API key (see /v1/admin/bind-fd-user). Body value is IGNORED on the public route unless X-Internal-Secret matches. Kept on the schema for the internal admin path only.",
"type": "string"
},
"lineups": {
"anyOf": [
{
"type": "integer",
"maximum": 150,
"minimum": 1
},
{
"type": "null"
}
],
"title": "lineups",
"description": "Number of lineups (overrides preset default)",
"type": "integer"
},
"strategy": {
"anyOf": [
{
"type": "string",
"pattern": "^(gpp|cash)$"
},
{
"type": "null"
}
],
"title": "strategy",
"description": "GPP or cash game strategy",
"type": "string"
},
"style": {
"anyOf": [
{
"type": "string",
"pattern": "^(aggressive|balanced|safe)$"
},
{
"type": "null"
}
],
"title": "style",
"type": "string"
},
"runs": {
"type": "integer",
"maximum": 10,
"minimum": 1,
"title": "runs",
"description": "Accepted for tier limits and response metadata. Portfolio quality is controlled by preset, candidate_pool_size, pool_oversample_multiplier, and simulation settings.",
"default": 5
},
"seed": {
"type": "integer",
"maximum": 999999,
"minimum": 0,
"title": "seed",
"description": "Random seed for reproducibility",
"default": 42
},
"locks": {
"items": {},
"type": "array",
"maxItems": 15,
"title": "locks",
"description": "Players to lock in",
"default": []
},
"avoids": {
"items": {},
"type": "array",
"maxItems": 100,
"title": "avoids",
"description": "Players to avoid",
"default": []
},
"exposure_caps": {
"additionalProperties": true,
"type": "object",
"title": "exposure_caps",
"description": "Per-player exposure caps {name: 0.0-1.0}",
"default": {}
},
"max_hitter_exposure": {
"anyOf": [
{
"type": "number",
"maximum": 1,
"exclusiveMinimum": 0
},
{
"type": "null"
}
],
"title": "max_hitter_exposure",
"description": "Portfolio cap: max share of delivered lineups any ONE hitter may appear in (0.4 = 40%). Pitchers exempt.",
"type": "number"
},
"max_pitcher_exposure": {
"anyOf": [
{
"type": "number",
"maximum": 1,
"exclusiveMinimum": 0
},
{
"type": "null"
}
],
"title": "max_pitcher_exposure",
"description": "Portfolio cap: max share of delivered lineups any ONE pitcher may appear in.",
"type": "number"
},
"auto_team_exposure_cap": {
"anyOf": [
{
"type": "number",
"maximum": 1,
"exclusiveMinimum": 0
},
{
"type": "null"
}
],
"title": "auto_team_exposure_cap",
"description": "Default per-team portfolio cap (share of lineups containing ANY given team). Per-team entries in team_exposure_caps win over it.",
"type": "number"
},
"team_exposure_caps": {
"anyOf": [
{
"items": {
"prefixItems": [
{
"type": "string"
},
{
"type": "number"
}
],
"type": "array",
"maxItems": 2,
"minItems": 2
},
"type": "array"
},
{
"additionalProperties": {
"type": "number"
},
"type": "object"
},
{
"type": "null"
}
],
"title": "team_exposure_caps",
"description": "Per-team portfolio caps, as [[\"COL\",0.5],...] pairs or {\"COL\":0.5} dict.",
"type": "object"
},
"focus_games": {
"items": {
"type": "string"
},
"type": "array",
"maxItems": 30,
"title": "focus_games",
"description": "Game keys to emphasize, e.g. ['PHI@BOS']. Applies a small documented projection nudge.",
"default": []
},
"projection_overrides": {
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array",
"maxItems": 2000,
"title": "projection_overrides",
"description": "User-uploaded projection/ownership rows. Supports name/player_id/team/position/projection/ownership/ceiling/floor/stddev.",
"default": []
},
"sim_mode": {
"anyOf": [
{
"type": "string",
"pattern": "^(off|mvn|on)$"
},
{
"type": "null"
}
],
"title": "sim_mode",
"description": "Simulation mode. NBA: mvn/off. MLB: on/off.",
"type": "string"
},
"n_sims": {
"anyOf": [
{
"type": "integer",
"maximum": 100000,
"minimum": 100
},
{
"type": "null"
}
],
"title": "n_sims",
"description": "Monte Carlo iterations when simulation is enabled.",
"type": "integer"
},
"candidate_pool_size": {
"anyOf": [
{
"type": "integer",
"maximum": 5000,
"minimum": 0
},
{
"type": "null"
}
],
"title": "candidate_pool_size",
"description": "Exact candidate pool size for Pool→Rank→Keep-N selection. 0/None uses preset multiplier.",
"type": "integer"
},
"pool_oversample_multiplier": {
"anyOf": [
{
"type": "number",
"maximum": 10,
"minimum": 1
},
{
"type": "null"
}
],
"title": "pool_oversample_multiplier",
"description": "Candidate pool multiplier when candidate_pool_size is not set.",
"type": "number"
},
"refresh_data": {
"type": "boolean",
"title": "refresh_data",
"description": "Force a fresh V12 data refresh for user-facing generation. Backtests should set false.",
"default": true
},
"allow_locked": {
"type": "boolean",
"title": "allow_locked",
"description": "Explicit replay/late-swap override. Default false blocks slate_id generation once any game has started.",
"default": false
}
},
"required": [
"date"
],
"title": "generate_lineupsArguments"
}⚪run_mlb_postmortem(date, game_id, history_csv, history_filename, upload_csvs, ...)
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": {} } ] } ```
입력 스키마
{
"type": "object",
"properties": {
"date": {
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$",
"title": "date",
"description": "Slate date YYYY-MM-DD"
},
"game_id": {
"type": "string",
"maxLength": 32,
"minLength": 3,
"title": "game_id",
"description": "V12 slate/game handle, e.g. 129715."
},
"history_csv": {
"type": "string",
"minLength": 1,
"title": "history_csv",
"description": "Raw FanDuel contest-history CSV content."
},
"history_filename": {
"type": "string",
"maxLength": 240,
"title": "history_filename",
"default": "contest-history.csv"
},
"upload_csvs": {
"items": {
"properties": {
"filename": {
"type": "string",
"maxLength": 240,
"title": "Filename",
"default": "upload.csv"
},
"content": {
"type": "string",
"minLength": 1,
"title": "Content",
"description": "Raw FanDuel upload/template CSV content."
}
},
"type": "object",
"required": [
"content"
],
"title": "PostmortemUploadCsv"
},
"type": "array",
"maxItems": 20,
"title": "upload_csvs",
"default": []
},
"sabersim_csv": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "sabersim_csv",
"description": "Optional external lineup export for comparison.",
"type": "string"
},
"top_field_rank": {
"type": "integer",
"maximum": 1000,
"minimum": 1,
"title": "top_field_rank",
"default": 200
},
"sync_supabase": {
"type": "boolean",
"title": "sync_supabase",
"description": "Upsert simulator training rows to production store when configured.",
"default": true
}
},
"required": [
"date",
"game_id",
"history_csv"
],
"title": "run_mlb_postmortemArguments"
}🟢list_contests(platform, sport)
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": {} } ] } ```
입력 스키마
{
"type": "object",
"properties": {
"platform": {
"type": "string",
"default": "fd",
"title": "platform"
},
"sport": {
"type": "string",
"default": "MLB",
"title": "sport"
}
},
"title": "list_contestsArguments"
}🟢list_live_contests(platform, sport, compact, limit)
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": {} } ] } ```
입력 스키마
{
"type": "object",
"properties": {
"platform": {
"type": "string",
"default": "fd",
"title": "platform"
},
"sport": {
"type": "string",
"default": "MLB",
"title": "sport"
},
"compact": {
"type": "boolean",
"default": true,
"title": "compact"
},
"limit": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": 250,
"title": "limit",
"type": "integer"
}
},
"title": "list_live_contestsArguments"
}⚪contest_semaforo(platform, sport, limit)
Contest Semaforo VIP-only: per-contest play/skip verdict from the owner's verified P&L bands + structure gates + rake/fill math. See core/data/contest_semaforo. ### 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": {} } ] } ```
입력 스키마
{
"type": "object",
"properties": {
"platform": {
"type": "string",
"default": "fd",
"title": "platform"
},
"sport": {
"type": "string",
"default": "MLB",
"title": "sport"
},
"limit": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": 60,
"title": "limit",
"type": "integer"
}
},
"title": "contest_semaforoArguments"
}⚪scout_field(contest, min_days)
Scout Field VIP-only (owner order 8/16): opponent-scouting profiles for the small single-entry band. The owner's $65 table runs the SAME regulars nightly; this returns each regular's fingerprint — days seen, avg score, chalkiness (overlap with field consensus), favorite pitchers/bats and head-to-head vs the owner — built from harvested full fields (brain/scout_profiles.json, refreshed by the local scouting pipeline; packaged snapshot as fallback so the endpoint never 500s on a fresh volume). Same fail-closed allowlist as the semaforo. ### 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": {} } ] } ```
입력 스키마
{
"type": "object",
"properties": {
"contest": {
"type": "string",
"default": "Knuckleball",
"title": "contest"
},
"min_days": {
"type": "integer",
"default": 3,
"title": "min_days"
}
},
"title": "scout_fieldArguments"
}⚪contest_advice(name, platform, sport)
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": {} } ] } ```
입력 스키마
{
"type": "object",
"properties": {
"name": {
"type": "string",
"title": "name"
},
"platform": {
"type": "string",
"default": "fd",
"title": "platform"
},
"sport": {
"type": "string",
"default": "MLB",
"title": "sport"
}
},
"required": [
"name"
],
"title": "contest_adviceArguments"
}🟡fill_template(template_csv, lineups)
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": {} } ] } ```
입력 스키마
{
"type": "object",
"properties": {
"template_csv": {
"type": "string",
"maxLength": 8000000,
"title": "template_csv",
"description": "Raw CSV of the entries-template (headers + entry rows)."
},
"lineups": {
"items": {
"items": {
"type": "string"
},
"type": "array"
},
"type": "array",
"maxItems": 200,
"title": "lineups",
"description": "Each lineup = upload tokens in template roster-slot order."
}
},
"required": [
"template_csv",
"lineups"
],
"title": "fill_templateArguments"
}⚪admin_issue_key(email, tier, rotate)
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": {} } ] } ```
입력 스키마
{
"type": "object",
"properties": {
"email": {
"type": "string",
"maxLength": 200,
"minLength": 5,
"title": "email"
},
"tier": {
"type": "string",
"pattern": "^(starter|personal|business)$",
"title": "tier",
"default": "personal"
},
"rotate": {
"type": "boolean",
"title": "rotate",
"description": "Revoke existing keys and mint a fresh one.",
"default": false
}
},
"required": [
"email"
],
"title": "admin_issue_keyArguments"
}🟢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
입력 스키마
{
"type": "object",
"properties": {},
"title": "betting_agent_guideArguments"
}⚪betting_player_form(name, season)
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": {} } ] } ```
입력 스키마
{
"type": "object",
"properties": {
"name": {
"type": "string",
"title": "name"
},
"season": {
"type": "integer",
"default": 2026,
"title": "season"
}
},
"required": [
"name"
],
"title": "betting_player_formArguments"
}🟢betting_analyze_prop(name, prop, threshold, season)
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": {} } ] } ```
입력 스키마
{
"type": "object",
"properties": {
"name": {
"type": "string",
"title": "name"
},
"prop": {
"type": "string",
"default": "home_run",
"title": "prop"
},
"threshold": {
"type": "integer",
"default": 2,
"title": "threshold"
},
"season": {
"type": "integer",
"default": 2026,
"title": "season"
}
},
"required": [
"name"
],
"title": "betting_analyze_propArguments"
}⚪betting_scan_edges(prop, min_edge, limit, threshold, coors, ...)
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": {} } ] } ```
입력 스키마
{
"type": "object",
"properties": {
"prop": {
"type": "string",
"default": "home_run",
"title": "prop"
},
"min_edge": {
"type": "number",
"default": 2,
"title": "min_edge"
},
"limit": {
"type": "integer",
"default": 15,
"title": "limit"
},
"threshold": {
"type": "integer",
"default": 2,
"title": "threshold"
},
"coors": {
"type": "boolean",
"default": false,
"title": "coors"
},
"season": {
"type": "integer",
"default": 2026,
"title": "season"
}
},
"title": "betting_scan_edgesArguments"
}⚪betting_best_bets(min_edge, limit)
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": {} } ] } ```
입력 스키마
{
"type": "object",
"properties": {
"min_edge": {
"type": "number",
"default": 2,
"title": "min_edge"
},
"limit": {
"type": "integer",
"default": 12,
"title": "limit"
}
},
"title": "betting_best_betsArguments"
}🟢betting_build_parlay(legs, ticket_odds)
Build Parlay Deterministic parlay analysis for BOTH leg shapes. Body: {legs:[...], ticket_odds?}. PROP legs {name, prop, threshold} keep the legacy correlation-aware EV. GAME-side legs (ML / run line / total / team total / F5, selected by the `market` field) — the slips users actually paste — are priced from the CURRENT de-vigged market at that exact market/ line (canonical team resolution), falling back to the market-anchored run model for totals; per-leg fair prob + edge vs the slip's price, combined payout / breakeven / fair prob / EV under a documented independence assumption. Legs sharing a game are flagged correlated=true and get a correlation_warning INSTEAD of a combined edge. ticket_odds (the slip's printed combined price) is verified vs the leg product — >2% off flags ticket_odds_mismatch (the slip was misread; do not trust the numbers). NEVER estimate a parlay in prose — this endpoint is the math. ### 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": {} } ] } ```
입력 스키마
{
"type": "object",
"properties": {
"legs": {
"items": {
"properties": {
"name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Name"
},
"prop": {
"type": "string",
"title": "Prop",
"default": "home_run"
},
"threshold": {
"type": "integer",
"title": "Threshold",
"default": 2
},
"market": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Market"
},
"team": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Team"
},
"side": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Side"
},
"line": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"title": "Line"
},
"american_odds": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"title": "American Odds"
}
},
"type": "object",
"title": "_ParlayLeg",
"description": "One parlay leg — TWO shapes, discriminated by the `market` field.\n\nPROP leg (legacy): {name, prop, threshold?}\nGAME-side leg (C12): {market: moneyline|run_line|total|team_total|\n f5_moneyline|f5_total, team, side: over/under/home/\n away/<team>, line?, american_odds (the SLIP's price —\n authoritative for the payout math)}."
},
"type": "array",
"title": "legs"
},
"ticket_odds": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"title": "ticket_odds",
"type": "integer"
}
},
"required": [
"legs"
],
"title": "betting_build_parlayArguments"
}⚪betting_log_bet(uid, market, selection, odds, stake, ...)
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": {} } ] } ```
입력 스키마
{
"type": "object",
"properties": {
"uid": {
"type": "string",
"title": "uid"
},
"market": {
"type": "string",
"title": "market"
},
"selection": {
"type": "string",
"title": "selection"
},
"odds": {
"type": "integer",
"title": "odds"
},
"stake": {
"type": "number",
"title": "stake"
},
"line": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"title": "line",
"type": "number"
},
"prop": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "prop",
"type": "string"
},
"team": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "team",
"type": "string"
},
"game": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "game",
"type": "string"
},
"book": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "book",
"type": "string"
}
},
"required": [
"uid",
"market",
"selection",
"odds",
"stake"
],
"title": "betting_log_betArguments"
}⚪betting_my_bets(uid)
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": {} } ] } ```
입력 스키마
{
"type": "object",
"properties": {
"uid": {
"type": "string",
"title": "uid"
}
},
"required": [
"uid"
],
"title": "betting_my_betsArguments"
}🟢betting_settle_bet(uid, bet_id, result, closing_odds)
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": {} } ] } ```
입력 스키마
{
"type": "object",
"properties": {
"uid": {
"type": "string",
"title": "uid"
},
"bet_id": {
"type": "string",
"title": "bet_id"
},
"result": {
"type": "string",
"title": "result"
},
"closing_odds": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"title": "closing_odds",
"type": "integer"
}
},
"required": [
"uid",
"bet_id",
"result"
],
"title": "betting_settle_betArguments"
}⚪betting_cross_book(prop)
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": {} } ] } ```
입력 스키마
{
"type": "object",
"properties": {
"prop": {
"type": "string",
"default": "pitcher_strikeouts",
"title": "prop"
}
},
"title": "betting_cross_bookArguments"
}⚪betting_game_lines(team, date)
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": {} } ] } ```
입력 스키마
{
"type": "object",
"properties": {
"team": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "team",
"type": "string"
},
"date": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "date",
"type": "string"
}
},
"title": "betting_game_linesArguments"
}🟢betting_market(team, date)
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": {} } ] } ```
입력 스키마
{
"type": "object",
"properties": {
"team": {
"type": "string",
"title": "team"
},
"date": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "date",
"type": "string"
}
},
"required": [
"team"
],
"title": "betting_marketArguments"
}⚪betting_sharp(team, date)
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": {} } ] } ```
입력 스키마
{
"type": "object",
"properties": {
"team": {
"type": "string",
"title": "team"
},
"date": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "date",
"type": "string"
}
},
"required": [
"team"
],
"title": "betting_sharpArguments"
}⚪betting_game_model(team, date)
Game Model MODEL the GAME run markets — TEAM TOTALS (over/under) and NRFI/YRFI — vs the FanDuel line, MARKET-ANCHORED: expected_runs = the book's de-vigged implied mean + 0.25×(structural model − book), and every edge is computed vs the FAIR (de-vigged) probability, never the raw vig price. The structural inputs (season runs/game, opposing STARTER + BULLPEN run factors, park; negative-binomial tails) supply only the tilt. Entries with anchored=false / model_only=true carry edge=null — present them as context, NEVER as value. 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": {} } ] } ```
입력 스키마
{
"type": "object",
"properties": {
"team": {
"type": "string",
"title": "team"
},
"date": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "date",
"type": "string"
}
},
"required": [
"team"
],
"title": "betting_game_modelArguments"
}⚪betting_matchup(team, date)
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": {} } ] } ```
입력 스키마
{
"type": "object",
"properties": {
"team": {
"type": "string",
"title": "team"
},
"date": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "date",
"type": "string"
}
},
"required": [
"team"
],
"title": "betting_matchupArguments"
}⚪betting_market_movers(prop, min_move, date)
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": {} } ] } ```
입력 스키마
{
"type": "object",
"properties": {
"prop": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "prop",
"type": "string"
},
"min_move": {
"type": "number",
"default": 3,
"title": "min_move"
},
"date": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "date",
"type": "string"
}
},
"title": "betting_market_moversArguments"
}커뮤니티
증거