Production-minded MCP server + CLI for live sportsbook data ingestion, movement analysis, ranking, and AI-agent workflows.

SSB MCP ── Sharp Money Intelligence for AI Agents

SSB MCP is a Model Context Protocol server that lets AI agents see what the sharpest sportsbooks are doing. Its current registry covers 39 screen feeds across 12 league configs, detects coordinated sharp movement, surfaces steam moves and line lags, and explains the consensus — so you can decide what to bet, not be told.

Connect it to Claude Desktop, Cursor, Cline, Hermes, or any MCP client. Requires a PropProfessor account — the free tier is enough; no paid subscription needed.

Honest scope — no profitability claim: SSB MCP is a sharp-signal DISCOVERY and RATING tool. tier / kaiCall / edge / screenScore are signal-quality ratings, not win-probability predictions. Profitability is UNPROVEN — no settled-results backtest has been published yet. Use it to find candidate plays and validate them yourself; do not treat outputs as a guaranteed winning system. The ranking pipeline surfaces what sharp books are doing; the betting decision stays with you.

What this project demonstrates

  • Agent integration — a 31-tool MCP surface with natural-language routing and structured responses
  • Data pipelines — live odds extraction, line-history hydration, consensus scoring, and market-specific ranking
  • Operational reliability — auth recovery, circuit breakers, caching, validation, and deterministic install checks
  • Honest evaluation — synthetic validation is separated from real settled-results backtesting; unsupported win-rate claims are deliberately avoided

🚀 Overview

Your AI agent gets 31 tools that surface the same signal feed professional bettors use:

  • Screen & rank — query the current 39-feed screen registry, ranked by consensus edge and movement
  • Detect sharp coordination — Pinnacle, Circa, BookMaker, and BetOnline moving together? That's a signal
  • Explain the "why" — every play comes with a human-readable rationale: what moved, on which books, over what timeframe
  • Natural language routing — agents call ask("best plays on Fliff tonight") and get routed to the right tool automatically

The pipeline extracts odds, hydrates line history, ranks by movement quality + consensus strength, assigns a tier and risk score, and returns everything your agent needs to present an informed recommendation. The betting decision stays with the human.

⚡ Quickstart (30 seconds)

  1. Clone and install: git clone https://github.com/jbdrak/ssb-for-agents.git && cd ssb-for-agents && npm ci && npm link

  2. Wire your MCP client — pick your client below:

    Claude Desktop (claude_desktop_config.json):

    {
      "mcpServers": {
        "ssb": {
          "command": "pp",
          "args": ["--mcp"]
        }
      }
    }
    

    Cline (cline_mcp_settings.json):

    {
      "mcpServers": {
        "ssb": {
          "command": "pp",
          "args": ["--mcp"],
          "env": {}
        }
      }
    }
    

    Cursor — Settings → Features → MCP Servers → Add:

    Name: ssb
    Type: command
    Command: pp --mcp
    

    Continue.dev (~/.continue/config.json):

    {
      "experimental": {
        "mcpServers": {
          "ssb": {
            "command": "pp",
            "args": ["--mcp"]
          }
        }
      }
    }
    

    Hermes (~/.hermes/config.yaml):

    mcp_servers:
      ssb:
        command: pp
        args: [--mcp]
    
  3. Auth (one-time): node scripts/pp-login.js — opens a browser for PropProfessor login and persists cookies for the server to use.

  4. Ask your agent: "What are tonight's sharpest plays on Fliff?"

That's it — your agent now sees 31 tools.

Verify your install: npm run install:verify runs the credential-free install verification suite.

CLI — pp

SSB ships with a fast, standalone CLI that calls handlers directly — no MCP server needed.

git clone https://github.com/jbdrak/ssb-for-agents.git
cd ssb-for-agents
npm ci
npm link
pp scan mlb tennis -M supportive -n3

18 commands for scanning, validation, setup, and logging:

Command Description
pp scan [leagues...] Find plays across leagues
pp scan -M supportive Filter by movement (clean, bouncy, adverse)
pp scan --fast Quick scan (5 fastest leagues)
pp scan -B Only BET verdict plays
pp validate <playId> Validate a specific play
pp game <gameId> Get full game details
pp player <name> Player context + injury/risk flags
pp prices <gameId> Compare prices across books
pp log <gameId> Log a pick
pp picks Recent pick history
pp rank <league> Ranked plays for a league
pp fantasy Fantasy optimizer props
pp today Today's slate + pending picks
pp health Auth + backend health check
pp-mcp MCP server (stdio) — connect your AI agent
pp-query init One-command setup (Node check + auth + doctor + config)
pp-query login Browser login to SSB
pp-query doctor Full diagnostic check

MCP mode: pp --mcp runs as an MCP stdio server. Connect it to Claude Desktop,Cursor, Cline, or any MCP client. Pass --mode full for the full 31-tool surface.

Quick start (from a clone): after npm link, run pp --mcp to start the MCP server. No global package download is required.Development/clone setup: use the full path — node /path/to/scripts/ssb-mcp-server.js — see MCP Client Setup below.

All commands support -j/--json for piping and --no-color for CI/Telegram output.

Example output (scan filtered by supportive movement):

MLB › Moneyline  (2)
  Houston Astros @ +127  |  TIER 1  ● BET
    1.9%  ·  clv +4¢  ·  mv supportive_bouncy  ·  5 books
    Chicago White Sox vs Houston Astros  Fri, Jul 24, 6:40 PM

Tennis › Total Games  (1)
  Under 21.5 @ -104  |  TIER 1  ● BET
    3.4%  ·  mv supportive_clean  ·  16 books
    Avanesyan vs Oliynykova  Fri, Jul 24, 7:00 AM

📊 Backtesting

SSB includes a backtest runner that prints settled-pick performance across any date range.

# Show last 30 days of settled picks
node scripts/backtest-runner.js --days 30

# Show a specific date range
node scripts/backtest-runner.js --from 2026-06-01 --to 2026-07-20

# Or use the installed binary
pp-backtest --days 30

The runner reads from ~/.ssb-for-agents/picks.json — the same file used by pp log and pp picks. It shows total picks, settled records, win rate, P&L, and breakdowns by tier and league. It never fabricates ROI. If no settled picks exist in the range, it says so honestly.

📒 Record Keeping — legacy tracker migration

The local record ledger (PP_RECORD_LEDGER, default ~/.ssb-for-agents/tracker/ledger.json) is the v2 source of truth for official bets. To import the old Python tracker's settled bets (~/.ssb-for-agents/tracker/bets.json) into the v2 ledger:

# Preview what would be imported (dry-run is the default — writes nothing)
node scripts/migrate-tracker.js

# Machine-readable preview
node scripts/migrate-tracker.js --json

# Actually migrate (backs up the destination ledger first)
node scripts/migrate-tracker.js --apply

Safety properties:

  • Dry-run by default--apply is required to write anything; --dry-run is explicit and conflicts with --apply.
  • bets.json is never overwritten — it is read-only input, and the script refuses to run when the source and ledger paths resolve to the same file.
  • Timestamped backup — before --apply writes, the existing destination ledger is copied to ledger.json.bak-<timestamp> (no backup is needed on first migration).
  • Idempotent — legacy IDs are preserved, so re-running never double-counts.
  • No guessed dates — legacy records carry no event date (only loggedAt/settledAt), so migrated bets get eventDate: "unknown" and can never appear in strict date-filtered reviews. The complete original record is preserved verbatim in each bet's legacy metadata, along with the legacy id, status, and P&L (plUnits).

Active workflow — record, review, settle

The day-to-day recordkeeping loop is manual and local-only; nothing polls SSB in the background:

# 1. Record the scan — snapshots the scan + normalized candidates into the ledger
pp scan --record-scan

# 2. Promote reviewed decision cards (BET → official bet; LEAN/PASS update the candidate only)
pp record-card card.json
pp record-card --json '<payload>'          # inline card JSON (single card or array)

# 3. Review the ledger (local, read-only)
pp record stats    --date 2026-08-04 --json
pp record review   --date 2026-08-04
pp record pending  --date 2026-08-04

# 4. Settle official bets against supplied authoritative results
node scripts/settle-record.js --results results.json --date 2026-08-04 --dry-run

Key properties:

  • --record-scan is manual only — it records whenever you run pp scan --record-scan; there is no cron job or background poller hitting SSB on a schedule.
  • Only BET promotespp record-card turns explicit BET cards into official bet records; LEAN/PASS update the candidate without creating a bet. Re-importing an already-recorded card is a no-op (idempotent).
  • pp record is local and read-onlystats, review, and pending modes read the ledger with no network and no writes; --date filters by the America/Chicago calendar day of scheduled start, --json emits machine-readable output.
  • Settlement never calls SSBscripts/settle-record.js (and lib/record-settlement) contain no network code. You fetch results yourself (e.g. an ESPN scoreboard dump) and hand them over as a local JSON file; the script matches bets to final scores, computes P&L, and writes the ledger atomically. --dry-run reports without writing anything; --force re-settles bets that already have a settled status.
  • Results file provenance is required — the results file must be an object with non-empty top-level provider and sourceUrl plus an events array; bare event arrays are no longer accepted. A same-ID event never settles on its ID alone: it must also match the bet's participants and fall inside the scheduled date window, and event-specific source URLs are kept only when the top-level provenance is valid. Missing provenance is a CLI usage error (the ledger is never touched), and library callers receive pending records with a precise reason instead of a settlement.
  • PP_RECORD_LEDGER overrides the ledger path — every command above reads/writes $PP_RECORD_LEDGER when set, otherwise the default ~/.ssb-for-agents/tracker/ledger.json.

Offline record → settle → evaluate example

Run the complete lifecycle without credentials, network calls, or user-file writes:

node examples/record-settle-evaluate.js

The synthetic fixture records an immutable probability snapshot, promotes a reviewed card, settles it from supplied result data, and derives calibration from the v2 ledger. Its one-bet report is explicitly marked insufficient for accuracy or uplift claims. See Project status and evaluation roadmap for shipped capabilities and hard limits.

🏛 Architecture

SSB MCP follows a layered data pipeline:

API Layer

  • SSB Backend — authenticated REST API for live odds, line history, and fantasy data
  • ESPN Integration — live scores for tennis time correction and game verification
  • X / Google News — player context (injury news, tweets) for bet validation

Ranking Pipeline (Node.js)

  • Extract — parse raw odds payloads from the screen API, expand multi-book selections
  • Hydrate — use SharpOdds as the primary movement-history source, with the authenticated PP history path as a fail-closed fallback; cache board/history reads within the bounded request
  • Rank — score by consensus edge (% advantage over sharp consensus), CLV proxy (opening vs current line movement), and league-specific market priorities
  • Tier — assign TIER 1–4 based on movement grade (green/yellow/red) × risk score (1–10) × sharp book confirmation, with hysteresis to prevent thrashing
  • Format — output at three verbosity levels: minimal (plain English), standard (tier/edge/risk/rationale), full (raw movement data)

MCP Server (stdio)

  • JSON-RPC over stdio — standard MCP transport with Content-Length framing (NDJSON optional)
  • 31 tools — organized into situational, analytical, and research tiers
  • Server-side validation — enforces input schemas at the server, not trusting the client
  • Categorized errors — auth, backend, transport, validation, internal — each with structured recovery hints

Data Flow

flowchart LR
    subgraph BOOKS["39 Screen Feeds"]
        B1[Pinnacle]
        B2[Circa]
        B3[BookMaker]
        B4[BetOnline]
        B5[NoVigApp]
        B6[Fliff]
        BN[...33 more]
    end

    API[PropProfessor API]

    subgraph PIPE["Ranking Pipeline"]
        E[Extract odds]
        H[Hydrate with line history]
        R[Rank by movement + consensus]
        T[Tier + risk score]
    end

    subgraph OUTPUT["31 MCP Tools"];
        QS[quick_screen]
        T[today]
        SB[smart_bet]
        VP[validate_play]
        ASK[ask]
        OTH[...25 more]
    end

    CLIENT[Your AI Agent<br/>Claude / Cursor / Cline / Hermes]

    BOOKS --> API --> PIPE --> OUTPUT --> CLIENT
    CLIENT -. "you decide what to bet" .- BOOKS

🛠 Getting Started

Quick Start

git clone https://github.com/jbdrak/ssb-for-agents.git
cd ssb-for-agents
npm install
npm link
pp-query init          # auth + verification + config — all at once

pp-query init checks Node version, opens PropProfessor login if needed, runs doctor, and prints ready-to-paste MCP config for your client. Or do it step by step:

pp-query login         # browser login
pp-query doctor        # verify everything works

Requires a PropProfessor account — the free tier is sufficient. That's it — you're ready to connect your AI agent.

MCP Client Setup

Add to your client's MCP config:

{
  "mcpServers": {
    "ssb": {
      "command": "node",
      "args": ["/path/to/ssb-for-agents/scripts/ssb-mcp-server.js"],
      "env": {
        "SSB_MCP_NDJSON": "true",
        "AUTH_FILE": "/path/to/.ssb-for-agents/auth.json"
      }
    }
  }
}

Replace /path/to/ with your actual install path (e.g. /Users/you/projects/ssb-for-agents). Supports Claude Desktop, Cursor, Cline, Zed, Continue.dev, Windsurf, and any other stdio-based MCP client. See each client's docs for where MCP config lives.

For short-lived one-off sessions:

Clone the repository, install dependencies, and point your client at the server script:

{ "command": "node", "args": ["/path/to/ssb-for-agents/scripts/ssb-mcp-server.js"] }

Requires a local clone and a free PropProfessor account.

For headless/CI environments (no Chrome):

Set the SSB_COOKIES env var with your PropProfessor cookies exported as JSON. This bypasses the CDP/Chrome auth path entirely:

{
  "mcpServers": {
    "ssb": {
      "command": "node",
      "args": ["/path/to/ssb-for-agents/scripts/ssb-mcp-server.js"],
      "env": {
        "SSB_COOKIES": "[{\"name\":\"__Secure-next-auth.session-token\",\"value\":\"...\",\"domain\":\".propprofessor.com\"}]"
      }
    }
  }
}

Auth refresh fallbacks (optional). When the server-to-server token fetch is gated by Vercel (HTTP 429), the server self-heals via a logged-in browser. Fallback order is got-scrapingego-browserCDP: the ego-browser fallback (named task space pp-token-refresh, created on first use, unless SSB_EGO_TASK_SPACE is set to a positive integer task-space id) is tried first; the CDP fallback runs only if ego-browser fails. The CDP endpoint defaults to http://127.0.0.1:9222/json/version; set SSB_CDP_VERSION_URL (e.g. http://127.0.0.1:9333/json/version) to use a different Chrome-for-Testing listener. Both fallbacks are on-demand only — no polling.

Hermes Agent

If you use Hermes Agent:

make install          # register MCP server + install default config

Or manually: add ssb to your mcp_servers in config.yaml. The get_started tool provides on-demand workflow guidance.

Sharp-money alerts

SSB is manual-only. There is no supported cron, scheduled workflow,or background polling mode. Run quick_screen on demand when you want a freshresult.

🎯 The Natural Language Flow

ask is a query router — it parses natural language and returns a suggested tool + args, but it does NOT execute the tool. Your agent calls ask to figure out what to do, then makes the actual call:

You:  "Tell me the best plays on Fliff tonight"
Agent: ask({ query: "best plays on Fliff tonight" })
       → { parsed: { book: "Fliff" }, suggestedTool: "quick_screen", suggestedArgs: { books: ["Fliff"] } }
Agent: quick_screen({ books: ["Fliff"] })
       → [ranked plays with odds, edge, tier, risk, rationale — all on Fliff]
You say Agent asks ask → then calls Returns
"best plays on Novig" askquick_screen(books=["NovigApp"]) Playable bets with player context
"what should I bet today" askquick_screen(mode="recommended") TIER 1 & TIER 2 across major leagues
"Tatum over 29.5 points" askplayer_context(player="Tatum", sport="NBA") Injury/news risk check
"show me MLB sharp plays" askquick_screen(leagues=["MLB"], mode="sharp") Multi-sharp consensus plays
"line shop Celtics ML" askfind_best_price(league="NBA", market="ML", …) Best price across available books
"validate that Warriors spread play" askvalidate_play(league="NBA", gameId="…", …) BET/CONSIDER/PASS verdict

📊 Available Tools

Quick Situational Checks

Tool What it does
ask Parse natural language query into the right tool + args (router, does NOT execute — agent calls the suggested tool separately)
today One-call daily briefing: sharp slate + your pending picks + recent stats
get_started Returns recommended workflow for casual/intermediate/sharp users
get_market_registry List available markets for a sport, with per-book market names (e.g. Soccer → Draw No Bet)
quick_screen Best plays on any book with sharp consensus + player context
smart_bet One-call: play details + validate_play verdict + best price + staking
player_context Injury/availability check on a specific player
validate_play One-call verdict: re-fetches odds, checks injury news, returns BET/CONSIDER/PASS + playId + drift detection
mlb_game_context Starting pitchers, park factor, hourly weather, lineup lock for an MLB game
find_best_price Line-shop across all books for the best execution price
health_status Auth freshness and endpoint connectivity

get_market_registry returns main-line markets in the markets field and exact player/pitcher prop names in the propMarkets field. scan and quick_screen accept includeProps:true to merge those prop markets into a scan. Prop scans are manual-only because they increase backend fan-out and rate-limit risk.

Deeper Signal Analysis

Tool What it does
sharp_consensus Multi-window (1h–48h) sharp movement — is the move sustained?
screen_ranked Full ranked data for a (league, market) pair with consensus and movement metadata
all_slates Consolidated ranked list across multiple leagues in one call
league_presets Sport-specific ranking weights and sharp-book reference sets
get_alerts Line movement and steam move alerts since last check
ev_candidates Fast +EV discovery — validate on /screen afterward
ufc_card UFC card shortlist with official plays, best looks, and pass notes
smart_money Sharp action $ volume + per-side odds range per game (the signal the +EV feed hides)

Research & Bet Management

Tool What it does
get_play_details Line history for specific game IDs
staking_plan Fractional Kelly sizing (TIER 1: 2%, TIER 2: 1% of bankroll)
fantasy_optimizer DFS-style fantasy picks (PrizePicks, Underdog — requires Fantasy Optimizer sub)
log_pick / resolve_pick Track your own bet outcomes
place_bet Validate + log a play in ONE call; returns a pickId for settlement
get_pick_history / get_pick_stats View logged bets and win rate / P&L
manage_hidden_bets Hide/unhide bets on the fantasy table
clear_score_timeline Reset tier trajectory tracking for a fresh session

Output Tuning

Every tool accepts:

Parameter Values What it does
verbosity minimal standard full Controls explanation depth and field output
compact true / false Strips line history and debug payloads — reduces response size by ~90%
fields ["game", "edge", "tier"] Return only specified fields per row

quick_screen additionally accepts:

Parameter Values What it does
cardWindow today next all Date filter. today = today's slate plus any next-day matches merged in (flagged via nextDayMerged in the response). next = tomorrow only. all = every upcoming match, no date filtering. Default today.
maxPlaysPerGame 150 (default 2) Max plays shown per game in minimal verbosity (highest screenScore first). Raise it (e.g. 10) for full coverage of a game without a second call. standard/full verbosity always return every candidate regardless of this value.
parseable true/false (default true) When true, minimal verbosity includes a structured plays array alongside the summary — agents get both. Set false for summary-only.
includeResearch true/false (default true) Run player_context research on each returned play and attach riskFlag / riskSummary / topTweet in the research array. Research is scoped to the FINAL returned plays (post tier/kaiCall filter) and de-duplicated per game, so the research array always matches the plays you see — no full-slate payload blowup. Pass false to disable.
researchLimit 150 (default 50) Max final plays to run research on. Bounds payload size on large scans.

Player research is ON by default in quick_screen (pass includeResearch: false to disable). It's scoped to the final returned plays and de-duplicated per game, so research always maps 1:1 to what you got back. On a huge unfiltered scan, lower researchLimit or use lite if the response nears the transport cap.

cardWindow honesty: when today is alive and next-day rows are merged, the response reports cardWindow: "today" (not tomorrow's date) plus nextDayMerged: true and nextDayDate. Earlier builds mislabeled this as tomorrow — that bug is fixed.

Tier consistency: as of 2.8.x, tierCache is cleared at the start of every MCP screen call (quick_screen, screen_ranked, validate_play). A given play's tier is therefore stable within a call and recomputed fresh per call — no cross-call drift from stale hysteresis state.

verbosity: minimal returns a plain-English summary string WITH a structured plays array — agents get both human-readable text and machine-parseable data in one call. Each play in the array includes league, market, game, selection, odds, confidenceTier, edge, startCST, movementDisposition, and screenScore.

Tool Surface Modes

Set SSB_MCP_MODE at server boot to control how many tools the agent sees on tools/list:

Mode Default Tools exposed Best for
lite ✅ yes 15 Recommended for most users. Covers the full workflow (discover → drill-down → validate → track) without overwhelming the tool catalog.
full no 31 Power users — every discovery, screen, research, and admin tool. More tools but more noise for the agent to reason about.

Lite mode exposes: ask, smart_bet, quick_screen, today, find_best_price, validate_play, get_play_details, player_context, log_pick, get_pick_history, resolve_pick, get_market_registry, place_bet, sharp_alerts, health_status.

The tools/list response always includes a _meta block so agents can tell which mode is active:

{
  "tools": [...],
  "_meta": { "mode": "full", "toolCount": 31, "liteToolCount": 15, "fullToolCount": 31 }
}

Tool Categories

Every tool carries a category field that groups it by purpose — agents can use this to mentally cluster the surface rather than reading 29 individual descriptions:

Category Count Purpose Tools
discovery 6 Find plays (scout, multi-league, DFS, +EV) all_slates, ask, ev_candidates, fantasy_optimizer, get_market_registry, sharp_consensus
screen 5 Score / rank plays for a target book quick_screen, screen_ranked, smart_bet, staking_plan, ufc_card
drill_down 3 Deep dive on a specific play find_best_price, get_play_details, validate_play
research 3 Context data (player news, game weather, alerts) get_alerts, mlb_game_context, player_context
tracking 4 Personal bet log get_pick_history, get_pick_stats, log_pick, resolve_pick
admin 2 Bookkeeping (cache, hidden bets) clear_score_timeline, manage_hidden_bets
meta 3 Server info / workflow guides get_started, health_status, league_presets

Canonical vs Deprecated Param Names

A handful of params accept both a clean canonical name and a legacy alias — every existing call site keeps working, and new code can use the cleaner names:

Canonical (prefer) Deprecated alias Where
live is_live 13 tools — is_live is snake_case only on the MCP surface; the upstream backend still uses is_live on the wire
gameIds game_ids get_play_details only
targetBooks book, books, targetBook, targetBooksCsv quick_screen — service layer's resolveTargetBooks() accepts all 5 names

Deprecated aliases are documented in each schema's description field and are normalized to the canonical key at dispatch time. No code change required for existing callers.

🧪 How the Ranking Works

The pipeline grades every play in 5 steps:

  1. Movement grade — green (all sharp books aligned), yellow (some signals, some not), red (adverse)
  2. Risk score (1–10) — weighted from movement quality, consensus count, CLV strength, execution quality, and freshness
  3. Tier assignment — lookup table: green + low risk → TIER 1, green-yellow + moderate → TIER 2, yellow → TIER 3, red → TIER 4
  4. Hysteresis — a play doesn't thrash between TIER 1 and TIER 3 on small odds changes; tier trajectory is smoothed
  5. Sharp cross-reference — verifies target-book moves independently against non-target sharp books

Tier system:

Tier Label Meaning Stake
TIER 1 Lock Green movement, risk 1–3, BET call. All signals aligned. 2% of bankroll
TIER 2 Value Yellow-green movement, risk 3–5, BET or CONSIDER. Solid play. 1% of bankroll
TIER 3 Speculative Yellow movement, risk 5–7, usually CONSIDER. Skip or 0.25% max
TIER 4 Avoid Red movement, risk 7+, PASS call. Do not bet. 0% — no exceptions

Full methodology, weight tables, and the tier assignment lookup in docs/METHODOLOGY.md. Backtesting results in docs/BACKTESTING.md.

🔌 Integrations

See Quick Start for Hermes Agent setup. The MCP is self-documenting — agents call get_started to discover the right workflow.

Discord / Telegram Alerts

The Positive EV Command Center is a companion project that monitors SSB for high-EV slips and plays, then pushes them to Discord and Telegram in real-time. It uses the same auth session and API client.

pp-query CLI

pp-query is a standalone CLI for one-off queries without an MCP client. Soccer is queried from the generic Soccer backend feed; named competitions are filtered by their leagueName (the same model used by the frontend):

pp-query screen --league NBA --market Moneyline
pp-query screen --league EPL --market "Total Goals"
pp-query screen --league Soccer --league-name EPL --market "Total Goals"
pp-query recommended --leagues NBA,MLB
pp-query login
pp-query doctor

📈 Validation methodology

TL;DR: The infrastructure is in place. Real outcome data hasn't accumulated yet.

Two paths to validate the signal:

1. Synthetic engine validation — runs generated scenarios (sharp_move,stable_no_edge, adverse) through the full pipeline to confirm the tier systemactually differentiates quality:

node scripts/backtest-synthetic.js

2. Real outcome backtest — snapshot-based, since the PropProfessor API doesnot serve historical settled results. Take a pre-game odds snapshot daily, thenresolve outcomes as games settle:

# capture today's recommended plays
node scripts/daily-snapshot.js
# after games settle, apply win/loss/push via CSV
node scripts/resolve-outcomes.js --csv results.csv
# compute P&L, ROI, Sharpe, max drawdown from resolved data
node scripts/backtest.js --metrics data/snapshots.jsonl

The pipeline (daily-snapshot.js → settle games → resolve-outcomes.jsbacktest.js --metrics) is built and tested (full deterministic pipeline suitepasses). What's missing: real settled-results data. The synthetictier-validation run shows a TIER 1 hit rate of 51.4% over N=296 simulatedsamples — these validate the ranking engine, they do NOT prove profitability.

Honesty: tier/kaiCall/edge/screenScore are signal-quality ratings, notwin-probability predictions. Profitability is UNPROVEN — no settled-resultsbacktest has been published yet. The system surfaces what sharp books aredoing; it doesn't come with a bundled historical results feed. Don't trust awin rate you can't trace to settled bets. See docs/BACKTESTING.md.

🔧 Troubleshooting

Symptom Likely cause Fix
AUTH_ERROR on every call Auth token expired or invalid Run pp-query login to re-authenticate in the browser
CIRCUIT_BREAKER_OPEN Upstream API is down or rate-limited Wait ~30s for the half-open retry; if persistent, run pp-query doctor to check backend health
VALIDATION_ERROR Wrong parameter name or type Use the canonical param names (e.g. targetBooks, not book). See Deprecated Param Names
Empty results from quick_screen No sharp consensus plays on that book+league combo right now Remove kaiCall: ["BET"] to see CONSIDER/PASS rows too. Try a different book or league
scan returns nothing Market name mismatch per league Call get_market_registry({ sport: "NBA" }) to discover the correct market names
First quick_screen is slow (5–15s) Multi-league fan-out cache is cold Normal. Subsequent calls with identical args return <5ms from the response cache
Some tools are missing from tools/list Server booted in lite mode Set SSB_MCP_MODE=full on startup, or use pp --mcp --mode full
CIRCUIT_BREAKER_OPEN persists Circuit breaker threshold exceeded Increase SSB_CIRCUIT_BREAKER_THRESHOLD (default 5) or timeout (default 30s). See CONFIG.md
Debug logging needed Set SSB_DEBUG=1 to see request/response traces on stderr

Still stuck? Run pp-query doctor and open an issue with the output.

❓ FAQ

Does this tell me what to bet? No. It surfaces what sharp books are doing. The betting decision is yours.

Do I need a PropProfessor account? Yes, and the free account is enough. Live data works on the free tier at propprofessor.com — no paid subscription required.

What books does it cover? The code currently registers 39 screen feeds across 12 league configs. Some entries are alternate or specialized feeds rather than distinct sportsbooks. Sharp cross-reference: Pinnacle, Circa, BookMaker, BetOnline.

Is it free? Code is MIT-licensed, and a free PropProfessor account covers the data. There is no paid tier of the MCP itself.

Can I run it without an MCP client? Yes — pp doctor is a standalone CLI.

What if I find a bug? Run pp doctor first, then open an issue.

⭐ Support

This is free, MIT-licensed software. If it saves you time or makes you money:

No paid tier. No upsell. The whole codebase is open and the priority is making it better for the people who use it.

🔧 For Maintainers

npm test              # full deterministic suite passes (no exact count — see check:claims)
npm run test:coverage # ~82% statements
npm run lint          # clean
npm run format:check  # clean (npm run format to fix)
npm run check:version # verifies package.json ↔ CHANGELOG

Release: push a v* tag → CI runs lint + tests on Node 20 + 22 → publishes to npm → creates the GitHub release.

📚 Docs Index

Doc What it covers
README Quick start, auth, CLI reference, tool list, tuning, architecture
CONFIG.md Environment variables, book config, token compression
INSTALL.md Install, first-run setup, MCP client wiring
CONTRIBUTING.md How to add a tool, testing, PRs
MAINTAINERS.md Release process, smoke tests
docs/METHODOLOGY.md Full ranking math: movement grade → risk score → tier + hysteresis
docs/BACKTESTING.md Synthetic & real-outcome backtest methodology
docs/AGENT_PROMPT.md Full system prompt for AI agents using SSB
docs/agent-guide.md 5 patterns every AI agent needs (cheat-sheet)
docs/RESPONSE_SHAPES.md JSON response shapes for all tools
docs/HERMES_SKILL.md Hermes Agent integration skill
docs/PERFORMANCE.md Response size, latency benchmarks, token usage
docs/MARKET-BOOK-AVAILABILITY.md Which markets each book supports, per league
docs/RELEASES.md Historical "what's new" archive (frozen at v2.2.0); CHANGELOG.md is the authoritative version history
llms.txt AI agent discovery file (compact overview for LLMs)

📝 License

MIT. PropProfessor offers a free tier; this MCP is an unofficial client built by James Drake, not affiliated with PropProfessor.

MCP Server · Populars

MCP Server · New

    feder-cr

    aihawk

    Open-source AI browser agent for web automation, undetected by anti-bot systems: a web browsing agent on a stealth Firefox that is not flagged as a bot, not blocked, and does not trigger captchas. Plain-English tasks, computer-use agent, browser MCP for Claude Code and Gemini CLI.

    Community feder-cr
    LeandroPG19

    MemoryIndustry

    Persistent memory MCP server for AI agents — Rust, 19 tools, knowledge graph, Hebbian learning, episodic memory, contradiction detection, prospective triggers, Bayesian calibration, zero-config Docker setup.

    Community LeandroPG19
    btsouth

    Toolport

    Local-first MCP gateway. One port for every tool and every AI client: lazy discovery (~90% token savings), tool integrity + quarantine, secrets in the OS keychain.

    Community btsouth
    manavmishra

    zeroslop

    Open-source Agent Skill that scores AI-sounding writing 0–100, edits it with your assistant.

    Community manavmishra
    opldotdev

    BSV MCP

    An MCP Server for Bitcoin SV

    Community opldotdev