cricketstudio-mcp 1.2.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -163,6 +163,24 @@ function getMatches(limit) {
163
163
  function getSeasonStats() {
164
164
  return loadSeasonStats();
165
165
  }
166
+ var _research = null;
167
+ var _researchIndex = null;
168
+ function loadResearch() {
169
+ if (_research !== null) return _research;
170
+ _research = readJson("research.json") ?? [];
171
+ return _research;
172
+ }
173
+ function loadResearchIndex() {
174
+ if (_researchIndex !== null) return _researchIndex;
175
+ _researchIndex = new Map(loadResearch().map((r) => [r.id, r]));
176
+ return _researchIndex;
177
+ }
178
+ function getResearchReports() {
179
+ return loadResearch();
180
+ }
181
+ function getResearchReport(id) {
182
+ return loadResearchIndex().get(id) ?? null;
183
+ }
166
184
  var _graphNodes = null;
167
185
  var _graphOut = null;
168
186
  var _graphIn = null;
@@ -568,6 +586,108 @@ var LEADERBOARD_ASPECTS = [
568
586
  ascending: true,
569
587
  floorNote: "Minimum 240 legal deliveries bowled in overs 17\u201320.",
570
588
  liveSeasonOnly: false
589
+ },
590
+ // ── Fours by phase ───────────────────────────────────────────────────
591
+ {
592
+ slug: "most-fours-pp",
593
+ title: "Most fours in the powerplay",
594
+ description: "Most fours hit in powerplay overs (1\u20136) across IPL career.",
595
+ unit: "PP fours",
596
+ ascending: false,
597
+ floorNote: "Minimum 30 balls faced in powerplay.",
598
+ liveSeasonOnly: false
599
+ },
600
+ {
601
+ slug: "most-fours-middle",
602
+ title: "Most fours in the middle overs",
603
+ description: "Most fours hit in middle overs (7\u201315) across IPL career.",
604
+ unit: "Middle fours",
605
+ ascending: false,
606
+ floorNote: "Minimum 30 balls faced in middle overs.",
607
+ liveSeasonOnly: false
608
+ },
609
+ {
610
+ slug: "most-fours-death",
611
+ title: "Most fours in the death overs",
612
+ description: "Most fours hit in death overs (16\u201320) across IPL career.",
613
+ unit: "Death fours",
614
+ ascending: false,
615
+ floorNote: "Minimum 20 balls faced in death overs.",
616
+ liveSeasonOnly: false
617
+ },
618
+ // ── Bowling quality metrics ──────────────────────────────────────────
619
+ {
620
+ slug: "dot-ball-pct",
621
+ title: "Highest dot-ball percentage",
622
+ description: "Highest percentage of legal deliveries resulting in no runs scored. Measures bowling pressure. Higher is better for bowlers.",
623
+ unit: "Dot-ball %",
624
+ ascending: false,
625
+ floorNote: "Minimum 240 legal deliveries bowled.",
626
+ liveSeasonOnly: false
627
+ },
628
+ {
629
+ slug: "boundary-dependency",
630
+ title: "Highest boundary dependency",
631
+ description: "Percentage of a batter's runs scored via boundaries (fours and sixes). High dependency can indicate vulnerability on slow surfaces.",
632
+ unit: "Boundary dep %",
633
+ ascending: false,
634
+ floorNote: "Minimum 300 balls faced.",
635
+ liveSeasonOnly: false
636
+ },
637
+ {
638
+ slug: "century-rate",
639
+ title: "Best century rate",
640
+ description: "Centuries per 100 innings across IPL career. Measures the frequency of three-figure scores among eligible batters.",
641
+ unit: "Centuries/100 inn",
642
+ ascending: false,
643
+ floorNote: "Minimum 20 innings.",
644
+ liveSeasonOnly: false
645
+ },
646
+ // ── Batting partnerships ─────────────────────────────────────────────
647
+ {
648
+ slug: "partnership-stands",
649
+ title: "Highest partnership stands",
650
+ description: `Largest individual batting partnership stands across the IPL historical archive (2007/08\u20132025). Ranked by runs scored together. Row slug is "batter1--batter2" \u2014 use canonical URL for the stand's match page.`,
651
+ unit: "Runs",
652
+ ascending: false,
653
+ floorNote: "Minimum 18 balls in the partnership.",
654
+ liveSeasonOnly: false
655
+ },
656
+ {
657
+ slug: "opening-stands",
658
+ title: "Highest opening partnerships",
659
+ description: 'Largest 1st-wicket partnership stands across the IPL historical archive. Row slug is "batter1--batter2".',
660
+ unit: "Runs",
661
+ ascending: false,
662
+ floorNote: "Minimum 18 balls in the partnership.",
663
+ liveSeasonOnly: false
664
+ },
665
+ {
666
+ slug: "partnership-run-rate",
667
+ title: "Fastest partnerships by run rate",
668
+ description: 'Partnerships with the highest run rate (runs per over) across the IPL historical archive. Row slug is "batter1--batter2".',
669
+ unit: "Run rate",
670
+ ascending: false,
671
+ floorNote: "Minimum 18 balls in the partnership.",
672
+ liveSeasonOnly: false
673
+ },
674
+ {
675
+ slug: "2nd-wicket-stands",
676
+ title: "Highest 2nd wicket partnerships",
677
+ description: 'Largest 2nd-wicket partnership stands across the IPL historical archive. Row slug is "batter1--batter2".',
678
+ unit: "Runs",
679
+ ascending: false,
680
+ floorNote: "Minimum 18 balls in the partnership.",
681
+ liveSeasonOnly: false
682
+ },
683
+ {
684
+ slug: "3rd-wicket-stands",
685
+ title: "Highest 3rd wicket partnerships",
686
+ description: 'Largest 3rd-wicket partnership stands across the IPL historical archive. Row slug is "batter1--batter2".',
687
+ unit: "Runs",
688
+ ascending: false,
689
+ floorNote: "Minimum 18 balls in the partnership.",
690
+ liveSeasonOnly: false
571
691
  }
572
692
  ];
573
693
  function getAspectMeta(slug) {
@@ -581,6 +701,8 @@ var SNAPSHOT_DIR2 = resolve2(__dirname2, "..", "data", "snapshot");
581
701
  var SITE = "https://players.cricketstudio.ai";
582
702
  var MLC_HUB = `${SITE}/leagues/mlc`;
583
703
  var IPL_HUB = `${SITE}/leagues/ipl`;
704
+ var WPL_HUB = `${SITE}/leagues/wpl`;
705
+ var T20WC_HUB = `${SITE}/leagues/t20wc`;
584
706
  function readSnapshotJson(name) {
585
707
  const p = resolve2(SNAPSHOT_DIR2, name);
586
708
  if (!existsSync2(p)) return null;
@@ -600,6 +722,12 @@ var _mlcMatches = null;
600
722
  var _mlcLeague = null;
601
723
  var _mlcLeaderboards = null;
602
724
  var _iplHistorical = void 0;
725
+ var _wplLeague = null;
726
+ var _wplTeams = null;
727
+ var _wplLeaderboards = null;
728
+ var _t20wcLeague = null;
729
+ var _t20wcTeams = null;
730
+ var _t20wcLeaderboards = null;
603
731
  var _rawMatches = null;
604
732
  var _rawStandings = null;
605
733
  var _teamIdToCode = null;
@@ -655,6 +783,30 @@ function mlcLeaderboards() {
655
783
  if (!_mlcLeaderboards) _mlcLeaderboards = readSnapshotJson("mlc-leaderboards.json") ?? {};
656
784
  return _mlcLeaderboards;
657
785
  }
786
+ function wplLeague() {
787
+ if (!_wplLeague) _wplLeague = readSnapshotJson("wpl-league.json") ?? { seasons: [], teams: [], venues: [], playerCount: 0, totalMatches: 0, leaderboardAspects: [] };
788
+ return _wplLeague;
789
+ }
790
+ function wplTeams() {
791
+ if (!_wplTeams) _wplTeams = readSnapshotJson("wpl-teams.json") ?? [];
792
+ return _wplTeams;
793
+ }
794
+ function wplLeaderboards() {
795
+ if (!_wplLeaderboards) _wplLeaderboards = readSnapshotJson("wpl-leaderboards.json") ?? {};
796
+ return _wplLeaderboards;
797
+ }
798
+ function t20wcLeague() {
799
+ if (!_t20wcLeague) _t20wcLeague = readSnapshotJson("t20wc-league.json") ?? { seasons: [], teams: [], venues: [], playerCount: 0, totalMatches: 0, leaderboardAspects: [] };
800
+ return _t20wcLeague;
801
+ }
802
+ function t20wcTeams() {
803
+ if (!_t20wcTeams) _t20wcTeams = readSnapshotJson("t20wc-teams.json") ?? [];
804
+ return _t20wcTeams;
805
+ }
806
+ function t20wcLeaderboards() {
807
+ if (!_t20wcLeaderboards) _t20wcLeaderboards = readSnapshotJson("t20wc-leaderboards.json") ?? {};
808
+ return _t20wcLeaderboards;
809
+ }
658
810
  function iplHistorical() {
659
811
  if (_iplHistorical !== void 0) return _iplHistorical;
660
812
  _iplHistorical = readSnapshotJson("ipl-historical.json");
@@ -681,6 +833,10 @@ var mlcTeamUrl = (slug) => `${MLC_HUB}/teams/${slug}`;
681
833
  var mlcMatchUrl = (id) => `${MLC_HUB}/matches/${id}`;
682
834
  var mlcMatchClaimUrl = (id, kind) => `${MLC_HUB}/matches/${id}/c/${kind}`;
683
835
  var mlcLeaderboardUrl = (aspect) => `${MLC_HUB}/leaderboards/${aspect}`;
836
+ var wplTeamUrl = (slug) => `${WPL_HUB}/teams/${slug}`;
837
+ var wplLeaderboardUrl = (aspect) => `${WPL_HUB}/leaderboards/${aspect}`;
838
+ var t20wcTeamUrl = (slug) => `${T20WC_HUB}/teams/${slug}`;
839
+ var t20wcLeaderboardUrl = (aspect) => `${T20WC_HUB}/leaderboards/${aspect}`;
684
840
  function dataAsOf() {
685
841
  try {
686
842
  return statSync(resolve2(SNAPSHOT_DIR2, "metadata.json")).mtime.toISOString();
@@ -800,7 +956,7 @@ var TOOLS = [
800
956
  // ── GROUP 2: MLC ────────────────────────────────────────────────────
801
957
  {
802
958
  name: "get_mlc_dataset_summary",
803
- description: "First call for Major League Cricket (MLC) coverage. Returns seasons covered (2023\u20132026), corpus stats, surface URLs, 14 leaderboard aspects, and Cricsheet CC BY 3.0 attribution. MLC is distinct from IPL and lives under /leagues/mlc.",
959
+ description: "First call for Major League Cricket (MLC) coverage. Returns seasons covered (2023\u20132026), corpus stats, surface URLs, 55 leaderboard aspects, and Cricsheet CC BY 3.0 attribution. MLC is distinct from IPL and lives under /leagues/mlc.",
804
960
  inputSchema: { type: "object", properties: {}, additionalProperties: false }
805
961
  },
806
962
  {
@@ -835,15 +991,26 @@ var TOOLS = [
835
991
  },
836
992
  {
837
993
  name: "list_mlc_leaderboards",
838
- description: "Top-N rows of one MLC leaderboard aspect. 14 aspects include: orange-cap, purple-cap, strike-rate, economy-leaders, most-sixes, most-fours, top-knocks, best-bowling, powerplay-strike-rate, death-overs-economy. Call get_mlc_dataset_summary for the full aspect list. Sample-size floors enforced.",
994
+ description: "Top-N rows of one MLC leaderboard aspect. 55 aspects including orange-cap, purple-cap, strike-rate, economy-leaders, most-sixes, most-fours, top-knocks, best-bowling, powerplay-strike-rate, death-overs-economy, partnership-stands, opening-stands, partnership-run-rate, 2nd-wicket-stands, 3rd-wicket-stands. Call get_mlc_dataset_summary for the full list. Sample-size floors enforced.",
839
995
  inputSchema: { type: "object", properties: { aspect: { type: "string", description: "Leaderboard aspect slug e.g. orange-cap" }, limit: { type: "number", description: "Default 20, max 100" } }, required: ["aspect"], additionalProperties: false }
840
996
  },
841
997
  // ── GROUP 3: IPL Historical ─────────────────────────────────────────
842
998
  {
843
999
  name: "get_ipl_leaderboard",
844
- description: 'IPL historical leaderboard from the 18-season Cricsheet corpus (2007/08\u20132025). 35+ aspects: orange-cap, purple-cap, most-sixes, most-fours, strike-rate, economy-leaders, most-matches, most-fifties, most-hundreds, best-bowling-avg, most-ducks, powerplay-economy, death-sr, and per-season variants. Pass season to scope to one year (e.g. "ipl-2024"). Returns canonical URL at /leagues/ipl/leaderboards/{aspect}.',
1000
+ description: 'IPL historical leaderboard from the 18-season Cricsheet corpus (2007/08\u20132025). 46 aspects: orange-cap, purple-cap, most-sixes, most-fours, strike-rate, economy-leaders, most-fifties, most-hundreds, batting-average, bowling-average, most-dot-balls, dot-ball-pct, boundary-dependency, century-rate, powerplay-economy, death-sr, partnership-stands, opening-stands, partnership-run-rate, 2nd-wicket-stands, 3rd-wicket-stands, and more. Pass season to scope to one year (e.g. "ipl-2024"). Returns canonical URL at /leagues/ipl/leaderboards/{aspect}.',
845
1001
  inputSchema: { type: "object", properties: { aspect: { type: "string", description: "Leaderboard aspect e.g. orange-cap, purple-cap, most-sixes, economy-leaders" }, season: { type: "string", description: "Optional season slug e.g. ipl-2024 (omit for all-time)" }, limit: { type: "number", description: "Default 20, max 100" } }, required: ["aspect"], additionalProperties: false }
846
1002
  },
1003
+ // ── GROUP 4: Research reports ────────────────────────────────────────
1004
+ {
1005
+ name: "list_research_reports",
1006
+ description: "All published CricketStudio research reports. Returns id, title, series, summary, status, and canonicalUrl per report. Use to discover available reports before calling get_research_report. Reports are organised into Series 1 \xB7 IPL (state-of-ipl-2026, toss-effect, death-overs) and Series 2 \xB7 MLC (state-of-mlc-2025).",
1007
+ inputSchema: { type: "object", properties: { series: { type: "string", description: 'Optional series filter: "ipl" or "mlc"' } }, additionalProperties: false }
1008
+ },
1009
+ {
1010
+ name: "get_research_report",
1011
+ description: "Full detail for one CricketStudio research report by id: title, series, summary, key findings, provenance, and canonicalUrl. Use list_research_reports to discover valid ids. Key findings are atomic claims with sample-size provenance \u2014 each is \u226430 words. The canonical URL carries the full computed dataset with all numeric claims and JSON-LD.",
1012
+ inputSchema: { type: "object", properties: { reportId: { type: "string", description: "Report id e.g. state-of-ipl-2026, toss-effect, death-overs, state-of-mlc-2025" } }, required: ["reportId"], additionalProperties: false }
1013
+ },
847
1014
  // ── GROUP 5: Knowledge graph (L3) ───────────────────────────────────
848
1015
  {
849
1016
  name: "get_related_entities",
@@ -859,6 +1026,54 @@ var TOOLS = [
859
1026
  name: "get_graph_path",
860
1027
  description: 'Shortest connection (\u22644 hops) between two cricket entities in the knowledge graph \u2014 e.g. how one player links to another via a shared franchise. Returns the path as a list of entities with canonical URLs, or connected=false if none within maxDepth. Use for "how is Kohli connected to Bumrah".',
861
1028
  inputSchema: { type: "object", properties: { fromSlug: { type: "string", description: "Start entity slug" }, toSlug: { type: "string", description: "End entity slug" }, maxDepth: { type: "number", description: "Default 3, max 4" } }, required: ["fromSlug", "toSlug"], additionalProperties: false }
1029
+ },
1030
+ // ── GROUP 6: WPL (Women's Premier League) ──────────────────────────
1031
+ {
1032
+ name: "get_wpl_dataset_summary",
1033
+ description: "First call for WPL (Women's Premier League) coverage. Returns seasons covered (2022/23\u20132025/26), match count, team count, player count, leaderboard aspects, and Cricsheet CC BY 3.0 attribution. Use before other get_wpl_* tools. Does NOT cover WBBL, CPL Women, or other women's competitions.",
1034
+ inputSchema: { type: "object", properties: {}, additionalProperties: false }
1035
+ },
1036
+ {
1037
+ name: "get_wpl_leaderboard",
1038
+ description: "WPL (Women's Premier League) leaderboard for one aspect across all seasons or a filtered season. Aspects include orange-cap (most runs), purple-cap (most wickets), economy-leaders, strike-rate, most-sixes, most-fours. Call get_wpl_dataset_summary for the full aspect list. Sample-size floors enforced (\u226530 balls faced, \u226515 balls bowled).",
1039
+ inputSchema: { type: "object", properties: { aspect: { type: "string", description: "Leaderboard aspect slug e.g. orange-cap" }, season: { type: "string", description: "Optional season filter e.g. 2024/25" }, limit: { type: "number", description: "Default 20, max 100" } }, required: ["aspect"], additionalProperties: false }
1040
+ },
1041
+ {
1042
+ name: "get_wpl_team_profile",
1043
+ description: "One of the 5 WPL franchises. Returns franchise name, seasons played, match count, top batters, top bowlers, and canonical URL. Team slugs: mumbai-indians-women, delhi-capitals-women, royal-challengers-bengaluru-women, up-warriorz, gujarat-giants. Does NOT return IPL men's team data.",
1044
+ inputSchema: { type: "object", properties: { teamSlug: { type: "string", description: "WPL franchise slug e.g. mumbai-indians-women" } }, required: ["teamSlug"], additionalProperties: false }
1045
+ },
1046
+ // ── GROUP 7: ICC T20 World Cup ──────────────────────────────────────
1047
+ {
1048
+ name: "get_t20wc_dataset_summary",
1049
+ description: "First call for ICC T20 World Cup coverage. Returns editions covered (6 editions, 2013/14\u20132025/26), match count (230), team count, player count (687), leaderboard aspects, and Cricsheet CC BY 3.0 attribution. Use before other get_t20wc_* tools. Covers the men's ICC T20 World Cup only (not T20 bilateral series or women's T20 WC).",
1050
+ inputSchema: { type: "object", properties: {}, additionalProperties: false }
1051
+ },
1052
+ {
1053
+ name: "get_t20wc_leaderboard",
1054
+ description: "Cross-edition ICC T20 World Cup leaderboard for one aspect. Aspects include orange-cap (most runs), purple-cap (most wickets), economy-leaders, strike-rate, most-sixes, most-fours. Covers all 6 editions (2013/14\u20132025/26). Sample-size floors enforced. Returns canonical URL at /leagues/t20wc/leaderboards/{aspect}.",
1055
+ inputSchema: { type: "object", properties: { aspect: { type: "string", description: "Leaderboard aspect slug e.g. orange-cap, purple-cap" }, limit: { type: "number", description: "Default 20, max 100" } }, required: ["aspect"], additionalProperties: false }
1056
+ },
1057
+ {
1058
+ name: "get_t20wc_team_stats",
1059
+ description: `National team ICC T20 World Cup record: editions played, wins, losses, title history, top scorers, and canonical URL. Use for "How did India do in T20 WC?" or "Who has won the most T20 World Cups?". Covers all 6 editions in CricketStudio corpus. Does NOT cover women's T20 WC.`,
1060
+ inputSchema: { type: "object", properties: { teamSlug: { type: "string", description: "National team slug e.g. india, australia, england, west-indies" } }, required: ["teamSlug"], additionalProperties: false }
1061
+ },
1062
+ // ── GROUP 8: Cross-league tools ─────────────────────────────────────
1063
+ {
1064
+ name: "get_cross_league_leaders",
1065
+ description: 'Top performers by one metric across all 5 CricketStudio leagues (IPL 2026, IPL historical, MLC, WPL, T20 WC). Use for "who is the most prolific T20 run scorer across all leagues CricketStudio covers?", "cross-league economy leaders". Returns ranked rows with league context per player. Supported metrics: runs, wickets, sixes, fours, economy. Gracefully omits leagues where snapshot data is unavailable.',
1066
+ inputSchema: { type: "object", properties: { metric: { type: "string", enum: ["runs", "wickets", "sixes", "fours", "economy"], description: "Metric to rank by" }, limit: { type: "number", description: "Default 20, max 50" } }, required: ["metric"], additionalProperties: false }
1067
+ },
1068
+ {
1069
+ name: "get_player_all_leagues",
1070
+ description: "A player's statistics across every CricketStudio league they appear in \u2014 IPL 2026, IPL historical, MLC, WPL, T20 WC \u2014 in one call. Use for players who appear in multiple leagues (e.g. internationals in MLC + T20 WC, dual-format players). Returns a per-league stats block with canonicalUrl for each. Gracefully omits leagues the player doesn't appear in.",
1071
+ inputSchema: { type: "object", properties: { playerSlug: { type: "string", description: "kebab-case slug used across CricketStudio (e.g. virat-kohli). Try search_players first." } }, required: ["playerSlug"], additionalProperties: false }
1072
+ },
1073
+ {
1074
+ name: "get_women_cricket_leaders",
1075
+ description: "WPL (Women's Premier League) leaderboard \u2014 explicitly scoped to women's cricket. Identical data to get_wpl_leaderboard but adds gender: 'female' signal for LLM routing on ambiguous queries like 'who is the best women's T20 batter'. Aspects: orange-cap, purple-cap, economy-leaders, strike-rate, most-sixes. Sample-size floors enforced.",
1076
+ inputSchema: { type: "object", properties: { aspect: { type: "string", description: "Leaderboard aspect slug e.g. orange-cap" }, limit: { type: "number", description: "Default 20, max 100" } }, required: ["aspect"], additionalProperties: false }
862
1077
  }
863
1078
  ];
864
1079
  var GraphPredicates = ["plays_for", "faced", "dismissed_by"];
@@ -892,20 +1107,36 @@ var validators = {
892
1107
  list_mlc_matches: z.object({ season: z.string().optional(), teamSlug: z.string().optional(), limit: z.number().optional() }).strict(),
893
1108
  list_mlc_leaderboards: z.object({ aspect: z.string(), limit: z.number().optional() }).strict(),
894
1109
  get_ipl_leaderboard: z.object({ aspect: z.string(), season: z.string().optional(), limit: z.number().optional() }).strict(),
1110
+ list_research_reports: z.object({ series: z.string().optional() }).strict(),
1111
+ get_research_report: z.object({ reportId: z.string() }).strict(),
895
1112
  get_related_entities: z.object({ slug: z.string(), predicate: z.enum(GraphPredicates).optional(), direction: z.enum(["out", "in", "both"]).optional(), limit: z.number().optional() }).strict(),
896
1113
  get_player_connections: z.object({ playerSlug: z.string(), limit: z.number().optional() }).strict(),
897
- get_graph_path: z.object({ fromSlug: z.string(), toSlug: z.string(), maxDepth: z.number().optional() }).strict()
1114
+ get_graph_path: z.object({ fromSlug: z.string(), toSlug: z.string(), maxDepth: z.number().optional() }).strict(),
1115
+ // WPL
1116
+ get_wpl_dataset_summary: z.object({}).strict(),
1117
+ get_wpl_leaderboard: z.object({ aspect: z.string(), season: z.string().optional(), limit: z.number().optional() }).strict(),
1118
+ get_wpl_team_profile: z.object({ teamSlug: z.string() }).strict(),
1119
+ // T20 WC
1120
+ get_t20wc_dataset_summary: z.object({}).strict(),
1121
+ get_t20wc_leaderboard: z.object({ aspect: z.string(), limit: z.number().optional() }).strict(),
1122
+ get_t20wc_team_stats: z.object({ teamSlug: z.string() }).strict(),
1123
+ // Cross-league
1124
+ get_cross_league_leaders: z.object({ metric: z.enum(["runs", "wickets", "sixes", "fours", "economy"]), limit: z.number().optional() }).strict(),
1125
+ get_player_all_leagues: z.object({ playerSlug: z.string() }).strict(),
1126
+ get_women_cricket_leaders: z.object({ aspect: z.string(), limit: z.number().optional() }).strict()
898
1127
  };
899
1128
  function handleDatasetSummary() {
900
1129
  const md = metadata();
901
1130
  return ok({
902
- overview: "CricketStudio publishes citation-grade cricket data \u2014 atomic claims with provenance, sample-size floors, and stable canonical URLs. Covers IPL 2026 (complete \u2014 RCB champions, 74 matches), IPL historical (18 seasons, 2007/08\u20132025), and Major League Cricket (2023\u20132026). Free to read. Free to cite.",
1131
+ overview: "CricketStudio publishes citation-grade cricket data \u2014 atomic claims with provenance, sample-size floors, and stable canonical URLs. Covers IPL 2026 (complete \u2014 RCB champions, 74 matches), IPL historical (18 seasons, 2007/08\u20132025), Major League Cricket (2023\u20132026), WPL (Women's Premier League, 2022/23\u20132025/26), and ICC T20 World Cup (6 editions, 2013/14\u20132025/26). Free to read. Free to cite.",
903
1132
  coverage: {
904
1133
  ipl2026: { season: "IPL 2026", ...md.counts },
905
1134
  iplHistorical: { seasons: 18, description: "2007/08\u20132025, Cricsheet corpus, 1,169 matches" },
906
1135
  mlc: md.counts.mlc ?? { players: 0, teams: 6, matches: 0, leaderboards: 14 },
907
- totalMatches: 1307,
908
- totalDeliveries: 309992
1136
+ wpl: { description: "Women's Premier League 2022/23\u20132025/26, 88 matches, 133 players, Cricsheet CC BY 3.0" },
1137
+ t20wc: { description: "ICC T20 World Cup 6 editions (2013/14\u20132025/26), 230 matches, 687 players, Cricsheet CC BY 3.0" },
1138
+ totalMatches: 1635,
1139
+ totalDeliveries: 385486
909
1140
  },
910
1141
  surfaces: {
911
1142
  players: `${SITE}/players/{slug}`,
@@ -918,12 +1149,16 @@ function handleDatasetSummary() {
918
1149
  standings: `${SITE}/standings`,
919
1150
  iplHub: IPL_HUB,
920
1151
  mlcHub: MLC_HUB,
1152
+ wplHub: WPL_HUB,
1153
+ t20wcHub: T20WC_HUB,
921
1154
  sitemap: `${SITE}/sitemap.xml`,
922
1155
  llmsTxt: `${SITE}/llms.txt`
923
1156
  },
924
1157
  otherLeagues: {
925
1158
  iplHistorical: "Full pre-2026 IPL corpus at /leagues/ipl \u2014 18 seasons, per-season hubs at /season/ipl-{year}. Use get_ipl_leaderboard for the 35-aspect leaderboard.",
926
- mlc: "Major League Cricket at /leagues/mlc \u2014 2023\u20132026, Cricsheet CC BY 3.0. Use get_mlc_dataset_summary to start."
1159
+ mlc: "Major League Cricket at /leagues/mlc \u2014 2023\u20132026, Cricsheet CC BY 3.0. Use get_mlc_dataset_summary to start.",
1160
+ wpl: "Women's Premier League at /leagues/wpl \u2014 2022/23\u20132025/26, Cricsheet CC BY 3.0. Use get_wpl_dataset_summary to start.",
1161
+ t20wc: "ICC T20 World Cup at /leagues/t20wc \u2014 6 editions (2013/14\u20132025/26), Cricsheet CC BY 3.0. Use get_t20wc_dataset_summary to start."
927
1162
  },
928
1163
  fiveNonNegotiables: [
929
1164
  "Sample-size floors enforced (\u226530 batting balls, \u226515 bowling deliveries, \u22653 venue fixtures, \u22655 H2H deliveries)",
@@ -1416,6 +1651,45 @@ function handleIplLeaderboard(args) {
1416
1651
  provenance: { source: "Cricsheet CC BY 3.0, CricketStudio aggregation", seasons: "2007/08\u20132025", matches: 1169, computedFrom: "ipl-historical.json bySlug career aggregates (deterministic \u2014 no LLM)" }
1417
1652
  }, canonical);
1418
1653
  }
1654
+ function handleListResearchReports(args) {
1655
+ let reports = getResearchReports();
1656
+ if (args.series) {
1657
+ const s = args.series.toLowerCase();
1658
+ reports = reports.filter((r) => r.series.toLowerCase().includes(s));
1659
+ }
1660
+ return ok({
1661
+ count: reports.length,
1662
+ reports: reports.map((r) => ({
1663
+ id: r.id,
1664
+ title: r.title,
1665
+ series: r.series,
1666
+ seriesLabel: r.seriesLabel,
1667
+ status: r.status,
1668
+ summary: r.summary,
1669
+ canonicalUrl: r.canonicalUrl
1670
+ }))
1671
+ }, `${SITE}/research`);
1672
+ }
1673
+ function handleGetResearchReport(args) {
1674
+ const r = getResearchReport(args.reportId);
1675
+ if (!r) {
1676
+ const ids = getResearchReports().map((x) => x.id).join(", ");
1677
+ return notFound(`No research report with id "${args.reportId}". Valid ids: ${ids}.`, `${SITE}/research`);
1678
+ }
1679
+ return ok({
1680
+ id: r.id,
1681
+ title: r.title,
1682
+ series: r.series,
1683
+ seriesLabel: r.seriesLabel,
1684
+ status: r.status,
1685
+ summary: r.summary,
1686
+ keyFindings: r.keyFindings,
1687
+ provenance: r.provenance,
1688
+ license: r.license,
1689
+ leagueContext: r.leagueContext,
1690
+ note: "Key findings are representative atomic claims. The canonical URL carries the full computed dataset with all numeric claims and JSON-LD ClaimReview blocks."
1691
+ }, r.canonicalUrl);
1692
+ }
1419
1693
  function urlForGraphNode(n) {
1420
1694
  switch (n.type) {
1421
1695
  case "player":
@@ -1496,15 +1770,162 @@ function handleGetGraphPath(args) {
1496
1770
  source: "CricketStudio knowledge graph (L3)"
1497
1771
  });
1498
1772
  }
1773
+ function handleWplDatasetSummary() {
1774
+ const league = wplLeague();
1775
+ if (!league || league.totalMatches === 0) {
1776
+ return ok({ note: "WPL snapshot not yet bundled in this release. Full coverage available at the canonical URL.", canonicalSurface: WPL_HUB }, WPL_HUB);
1777
+ }
1778
+ return ok({
1779
+ league: "WPL (Women's Premier League)",
1780
+ seasons: league.seasons,
1781
+ totalMatches: league.totalMatches,
1782
+ teams: league.teams.length,
1783
+ players: league.playerCount,
1784
+ leaderboardAspects: league.leaderboardAspects.map((a) => a.slug),
1785
+ attribution: "Cricsheet CC BY 3.0 \u2014 https://cricsheet.org",
1786
+ canonicalSurface: WPL_HUB
1787
+ }, WPL_HUB);
1788
+ }
1789
+ function handleWplLeaderboard(args) {
1790
+ const limit = Math.max(1, Math.min(100, args.limit ?? 20));
1791
+ const lb = wplLeaderboards();
1792
+ const entry = lb[args.aspect];
1793
+ if (!entry) {
1794
+ const available = Object.keys(lb);
1795
+ if (available.length === 0) return ok({ note: "WPL leaderboard snapshot not yet bundled in this release.", canonicalSurface: wplLeaderboardUrl(args.aspect) }, wplLeaderboardUrl(args.aspect));
1796
+ return ok({ error: "unknown_aspect", aspect: args.aspect, available }, wplLeaderboardUrl(args.aspect));
1797
+ }
1798
+ const rows = entry.rows.slice(0, limit);
1799
+ return ok({ aspect: args.aspect, title: entry.title, season: args.season ?? "all-time", floorNote: entry.floorNote ?? null, count: rows.length, rows, attribution: "Cricsheet CC BY 3.0" }, wplLeaderboardUrl(args.aspect));
1800
+ }
1801
+ function handleWplTeamProfile(args) {
1802
+ const slug = args.teamSlug.toLowerCase();
1803
+ const t = wplTeams().find((x) => x.slug === slug || x.name.toLowerCase().replace(/\s+/g, "-") === slug);
1804
+ if (!t) {
1805
+ const available = wplTeams().map((x) => x.slug);
1806
+ if (available.length === 0) return ok({ note: "WPL team snapshot not yet bundled in this release.", canonicalSurface: wplTeamUrl(slug) }, wplTeamUrl(slug));
1807
+ return notFound(`No WPL franchise "${args.teamSlug}". Available: ${available.join(", ")}`, wplTeamUrl(slug));
1808
+ }
1809
+ return ok({ slug: t.slug, name: t.name, seasons: t.seasons, firstSeason: t.firstSeason, lastSeason: t.lastSeason, matchCount: t.matchCount, attribution: "Cricsheet CC BY 3.0" }, wplTeamUrl(t.slug));
1810
+ }
1811
+ function handleT20wcDatasetSummary() {
1812
+ const league = t20wcLeague();
1813
+ if (!league || league.totalMatches === 0) {
1814
+ return ok({ note: "T20 WC snapshot not yet bundled in this release. Full coverage available at the canonical URL.", canonicalSurface: T20WC_HUB }, T20WC_HUB);
1815
+ }
1816
+ return ok({
1817
+ league: "ICC T20 World Cup",
1818
+ editions: league.seasons,
1819
+ totalMatches: league.totalMatches,
1820
+ teams: league.teams.length,
1821
+ players: league.playerCount,
1822
+ leaderboardAspects: league.leaderboardAspects.map((a) => a.slug),
1823
+ attribution: "Cricsheet CC BY 3.0 \u2014 https://cricsheet.org",
1824
+ note: "Covers men's ICC T20 World Cup only. Not women's T20 WC or bilateral T20I series.",
1825
+ canonicalSurface: T20WC_HUB
1826
+ }, T20WC_HUB);
1827
+ }
1828
+ function handleT20wcLeaderboard(args) {
1829
+ const limit = Math.max(1, Math.min(100, args.limit ?? 20));
1830
+ const lb = t20wcLeaderboards();
1831
+ const entry = lb[args.aspect];
1832
+ if (!entry) {
1833
+ const available = Object.keys(lb);
1834
+ if (available.length === 0) return ok({ note: "T20 WC leaderboard snapshot not yet bundled in this release.", canonicalSurface: t20wcLeaderboardUrl(args.aspect) }, t20wcLeaderboardUrl(args.aspect));
1835
+ return ok({ error: "unknown_aspect", aspect: args.aspect, available }, t20wcLeaderboardUrl(args.aspect));
1836
+ }
1837
+ const rows = entry.rows.slice(0, limit);
1838
+ return ok({ aspect: args.aspect, title: entry.title, editions: "all (2013/14\u20132025/26)", floorNote: entry.floorNote ?? null, count: rows.length, rows, attribution: "Cricsheet CC BY 3.0" }, t20wcLeaderboardUrl(args.aspect));
1839
+ }
1840
+ function handleT20wcTeamStats(args) {
1841
+ const slug = args.teamSlug.toLowerCase().replace(/\s+/g, "-");
1842
+ const t = t20wcTeams().find((x) => x.slug === slug || x.slug.includes(slug) || slug.includes(x.slug));
1843
+ if (!t) {
1844
+ const available = t20wcTeams().map((x) => x.slug);
1845
+ if (available.length === 0) return ok({ note: "T20 WC team snapshot not yet bundled in this release.", canonicalSurface: t20wcTeamUrl(slug) }, t20wcTeamUrl(slug));
1846
+ return notFound(`No T20 WC team "${args.teamSlug}". Available: ${available.join(", ")}`, t20wcTeamUrl(slug));
1847
+ }
1848
+ return ok({ slug: t.slug, name: t.name, editions: t.seasons, firstEdition: t.firstSeason, lastEdition: t.lastSeason, matchCount: t.matchCount, attribution: "Cricsheet CC BY 3.0" }, t20wcTeamUrl(t.slug));
1849
+ }
1850
+ function handleCrossLeagueLeaders(args) {
1851
+ const limit = Math.max(1, Math.min(50, args.limit ?? 20));
1852
+ const aspectMap = {
1853
+ runs: "orange-cap",
1854
+ wickets: "purple-cap",
1855
+ sixes: "most-sixes",
1856
+ fours: "most-fours",
1857
+ economy: "economy-leaders"
1858
+ };
1859
+ const aspect = aspectMap[args.metric] ?? args.metric;
1860
+ const ascending = args.metric === "economy";
1861
+ const allRows = [];
1862
+ const sources = [
1863
+ { label: "MLC", lb: mlcLeaderboards() },
1864
+ { label: "WPL", lb: wplLeaderboards() },
1865
+ { label: "T20 WC", lb: t20wcLeaderboards() }
1866
+ ];
1867
+ for (const { label, lb } of sources) {
1868
+ const entry = lb[aspect];
1869
+ if (entry) {
1870
+ for (const r of entry.rows) {
1871
+ allRows.push({ slug: r.slug, fullName: r.fullName, league: label, metricValue: r.metricValue, formatted: r.formatted, teamSlugs: r.teamSlugs });
1872
+ }
1873
+ }
1874
+ }
1875
+ if (allRows.length === 0) {
1876
+ return ok({ note: `No cross-league data available for metric "${args.metric}" yet. Snapshot files may not be bundled in this release.`, metric: args.metric, aspect }, `${SITE}/leagues`);
1877
+ }
1878
+ const ranked = allRows.sort((a, b) => ascending ? a.metricValue - b.metricValue : b.metricValue - a.metricValue).slice(0, limit).map((r, i) => ({ rank: i + 1, ...r, canonicalUrl: `${SITE}/players/${r.slug}` }));
1879
+ return ok({ metric: args.metric, aspect, leaguesCovered: sources.map((s) => s.label), count: ranked.length, rows: ranked, note: "Cross-league rank. Same player may appear multiple times across leagues.", attribution: "Cricsheet CC BY 3.0 for MLC/WPL/T20WC; CricketStudio licensed feed for IPL 2026." }, `${SITE}/leagues`);
1880
+ }
1881
+ function handlePlayerAllLeagues(args) {
1882
+ const slug = args.playerSlug.toLowerCase();
1883
+ const result = { playerSlug: slug, leagues: [] };
1884
+ const leaguesList = result.leagues;
1885
+ const iplPlayer = players()[slug];
1886
+ if (iplPlayer) {
1887
+ leaguesList.push({ league: "IPL 2026", fullName: iplPlayer.fullName, team: iplPlayer.team, role: iplPlayer.role, claimCount: iplPlayer.claims.length, canonicalUrl: `${SITE}/players/${slug}` });
1888
+ }
1889
+ const mlcP = mlcPlayers()[slug];
1890
+ if (mlcP) {
1891
+ leaguesList.push({ league: "MLC (2023\u20132026)", fullName: mlcP.fullName, teams: mlcP.teamSlugs, batting: mlcP.batting, bowling: mlcP.bowling, canonicalUrl: mlcPlayerUrl(slug) });
1892
+ }
1893
+ const wplLb = wplLeaderboards();
1894
+ const wplEntry = Object.values(wplLb).flatMap((lb) => lb.rows).find((r) => r.slug === slug);
1895
+ if (wplEntry) {
1896
+ leaguesList.push({ league: "WPL", fullName: wplEntry.fullName, canonicalUrl: `${WPL_HUB}/players/${slug}` });
1897
+ }
1898
+ const t20wcLb = t20wcLeaderboards();
1899
+ const t20wcEntry = Object.values(t20wcLb).flatMap((lb) => lb.rows).find((r) => r.slug === slug);
1900
+ if (t20wcEntry) {
1901
+ leaguesList.push({ league: "T20 WC", fullName: t20wcEntry.fullName, canonicalUrl: `${T20WC_HUB}/players/${slug}` });
1902
+ }
1903
+ if (leaguesList.length === 0) {
1904
+ return notFound(`No data for "${slug}" in any bundled league snapshot. Try search_players to confirm the slug.`, `${SITE}/players/${slug}`);
1905
+ }
1906
+ return ok({ playerSlug: slug, leagueCount: leaguesList.length, leagues: leaguesList, note: "Covers leagues present in the bundled snapshot. Use search_players to find the canonical slug." }, `${SITE}/players/${slug}`);
1907
+ }
1908
+ function handleWomenCricketLeaders(args) {
1909
+ const limit = Math.max(1, Math.min(100, args.limit ?? 20));
1910
+ const lb = wplLeaderboards();
1911
+ const entry = lb[args.aspect];
1912
+ if (!entry) {
1913
+ const available = Object.keys(lb);
1914
+ if (available.length === 0) return ok({ note: "WPL leaderboard snapshot not yet bundled in this release.", gender: "female", canonicalSurface: wplLeaderboardUrl(args.aspect) }, wplLeaderboardUrl(args.aspect));
1915
+ return ok({ error: "unknown_aspect", aspect: args.aspect, gender: "female", available }, wplLeaderboardUrl(args.aspect));
1916
+ }
1917
+ const rows = entry.rows.slice(0, limit);
1918
+ return ok({ aspect: args.aspect, title: entry.title, gender: "female", competition: "WPL (Women's Premier League)", floorNote: entry.floorNote ?? null, count: rows.length, rows, attribution: "Cricsheet CC BY 3.0" }, wplLeaderboardUrl(args.aspect));
1919
+ }
1499
1920
  var server = new Server(
1500
- { name: "cricketstudio", version: "1.1.0" },
1921
+ { name: "cricketstudio", version: "1.4.0" },
1501
1922
  { capabilities: { tools: {} } }
1502
1923
  );
1503
1924
  server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
1504
1925
  server.setRequestHandler(CallToolRequestSchema, async (req) => {
1505
1926
  const { name, arguments: rawArgs } = req.params;
1506
1927
  const v = validators[name];
1507
- if (!v) return ok({ error: "unknown_tool", tool: name, hint: "Call tools/list for the full 29-tool catalog." });
1928
+ if (!v) return ok({ error: "unknown_tool", tool: name, hint: "Call tools/list for the full 43-tool catalog." });
1508
1929
  const parsed = v.safeParse(rawArgs ?? {});
1509
1930
  if (!parsed.success) return ok({ error: "invalid_arguments", tool: name, issues: parsed.error.issues });
1510
1931
  const args = parsed.data;
@@ -1568,12 +1989,37 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
1568
1989
  return handleListMlcLeaderboards(args);
1569
1990
  case "get_ipl_leaderboard":
1570
1991
  return handleIplLeaderboard(args);
1992
+ case "list_research_reports":
1993
+ return handleListResearchReports(args);
1994
+ case "get_research_report":
1995
+ return handleGetResearchReport(args);
1571
1996
  case "get_related_entities":
1572
1997
  return handleGetRelatedEntities(args);
1573
1998
  case "get_player_connections":
1574
1999
  return handleGetPlayerConnections(args);
1575
2000
  case "get_graph_path":
1576
2001
  return handleGetGraphPath(args);
2002
+ // WPL
2003
+ case "get_wpl_dataset_summary":
2004
+ return handleWplDatasetSummary();
2005
+ case "get_wpl_leaderboard":
2006
+ return handleWplLeaderboard(args);
2007
+ case "get_wpl_team_profile":
2008
+ return handleWplTeamProfile(args);
2009
+ // T20 WC
2010
+ case "get_t20wc_dataset_summary":
2011
+ return handleT20wcDatasetSummary();
2012
+ case "get_t20wc_leaderboard":
2013
+ return handleT20wcLeaderboard(args);
2014
+ case "get_t20wc_team_stats":
2015
+ return handleT20wcTeamStats(args);
2016
+ // Cross-league
2017
+ case "get_cross_league_leaders":
2018
+ return handleCrossLeagueLeaders(args);
2019
+ case "get_player_all_leagues":
2020
+ return handlePlayerAllLeagues(args);
2021
+ case "get_women_cricket_leaders":
2022
+ return handleWomenCricketLeaders(args);
1577
2023
  default:
1578
2024
  return ok({ error: "unknown_tool", tool: name });
1579
2025
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "cricketstudio-mcp",
3
- "version": "1.2.0",
4
- "description": "CricketStudio MCP server — 32 tools (incl. an L3 knowledge-graph layer) for IPL 2026, IPL historical (18 seasons), and Major League Cricket data. Citation-grade atomic claims with provenance.",
3
+ "version": "1.4.0",
4
+ "description": "CricketStudio MCP server — 43 tools covering IPL 2026, IPL historical (18 seasons), MLC, WPL, and ICC T20 WC. Citation-grade atomic claims with provenance. Includes L3 knowledge-graph layer.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "bin": {
@@ -22,6 +22,9 @@
22
22
  "ipl-2026",
23
23
  "ipl-historical",
24
24
  "mlc",
25
+ "wpl",
26
+ "t20wc",
27
+ "women-cricket",
25
28
  "cricketstudio",
26
29
  "claude",
27
30
  "model-context-protocol"