cricketstudio-mcp 1.0.2 → 1.2.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/LICENSE +26 -216
- package/README.md +198 -153
- package/data/snapshot/graph.json +22551 -0
- package/data/snapshot/meta.json +24 -24
- package/data/snapshot/metadata.json +16 -22
- package/data/snapshot/mlc-leaderboards.json +29317 -14836
- package/data/snapshot/mlc-league.json +170 -122
- package/data/snapshot/players.json +16923 -18232
- package/data/snapshot/season-stats.json +14958 -65129
- package/data/snapshot/team-h2h.json +1158 -1138
- package/data/snapshot/trends.json +1159 -1128
- package/data/snapshot/venues.json +143 -143
- package/dist/index.js +189 -5
- package/package.json +56 -55
|
@@ -1,144 +1,144 @@
|
|
|
1
|
-
[
|
|
2
|
-
{
|
|
3
|
-
"slug": "narendra-modi-stadium",
|
|
4
|
-
"name": "Narendra Modi Stadium",
|
|
5
|
-
"city": "Ahmedabad",
|
|
6
|
-
"matchCount":
|
|
7
|
-
"geo": {
|
|
8
|
-
"latitude": 23.0917,
|
|
9
|
-
"longitude": 72.5972,
|
|
10
|
-
"wikidataQid": "Q379935"
|
|
11
|
-
}
|
|
12
|
-
},
|
|
13
|
-
{
|
|
14
|
-
"slug": "wankhede-stadium",
|
|
15
|
-
"name": "Wankhede Stadium",
|
|
16
|
-
"city": "Mumbai",
|
|
17
|
-
"matchCount": 7,
|
|
18
|
-
"geo": {
|
|
19
|
-
"latitude": 18.9388,
|
|
20
|
-
"longitude": 72.8259,
|
|
21
|
-
"wikidataQid": "Q1067595"
|
|
22
|
-
}
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
"slug": "bharat-ratna-shri-atal-bihari-vajpayee-ekana-cricket-stadium",
|
|
26
|
-
"name": "Bharat Ratna Shri Atal Bihari Vajpayee Ekana Cricket Stadium",
|
|
27
|
-
"city": "Lucknow",
|
|
28
|
-
"matchCount": 7,
|
|
29
|
-
"geo": {
|
|
30
|
-
"latitude": 26.8467,
|
|
31
|
-
"longitude": 80.9462,
|
|
32
|
-
"wikidataQid": "Q26257057"
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
"slug": "arun-jaitley-stadium",
|
|
37
|
-
"name": "Arun Jaitley Stadium",
|
|
38
|
-
"city": "Delhi",
|
|
39
|
-
"matchCount": 7,
|
|
40
|
-
"geo": {
|
|
41
|
-
"latitude": 28.6379,
|
|
42
|
-
"longitude": 77.2425,
|
|
43
|
-
"wikidataQid": "Q582518"
|
|
44
|
-
}
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
"slug": "rajiv-gandhi-international-stadium",
|
|
48
|
-
"name": "Rajiv Gandhi International Stadium",
|
|
49
|
-
"city": "Hyderabad",
|
|
50
|
-
"matchCount": 7,
|
|
51
|
-
"geo": {
|
|
52
|
-
"latitude": 17.4068,
|
|
53
|
-
"longitude": 78.55,
|
|
54
|
-
"wikidataQid": "Q1419486"
|
|
55
|
-
}
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
"slug": "
|
|
59
|
-
"name": "
|
|
60
|
-
"city": "
|
|
61
|
-
"matchCount": 6,
|
|
62
|
-
"geo": {
|
|
63
|
-
"latitude":
|
|
64
|
-
"longitude":
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
"
|
|
81
|
-
"
|
|
82
|
-
"
|
|
83
|
-
"
|
|
84
|
-
|
|
85
|
-
"
|
|
86
|
-
"
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
"
|
|
92
|
-
"
|
|
93
|
-
"
|
|
94
|
-
"
|
|
95
|
-
|
|
96
|
-
"
|
|
97
|
-
"
|
|
98
|
-
}
|
|
99
|
-
},
|
|
100
|
-
{
|
|
101
|
-
"slug": "sawai-mansingh-stadium",
|
|
102
|
-
"name": "Sawai Mansingh Stadium",
|
|
103
|
-
"city": "Jaipur",
|
|
104
|
-
"matchCount": 4,
|
|
105
|
-
"geo": {
|
|
106
|
-
"latitude": 26.8867,
|
|
107
|
-
"longitude": 75.8067,
|
|
108
|
-
"wikidataQid": "Q1437432"
|
|
109
|
-
}
|
|
110
|
-
},
|
|
111
|
-
{
|
|
112
|
-
"slug": "
|
|
113
|
-
"name": "
|
|
114
|
-
"city": "
|
|
115
|
-
"matchCount":
|
|
116
|
-
"geo": {
|
|
117
|
-
"latitude":
|
|
118
|
-
"longitude":
|
|
119
|
-
"wikidataQid": "
|
|
120
|
-
}
|
|
121
|
-
},
|
|
122
|
-
{
|
|
123
|
-
"slug": "
|
|
124
|
-
"name": "
|
|
125
|
-
"city": "
|
|
126
|
-
"matchCount": 3,
|
|
127
|
-
"geo": {
|
|
128
|
-
"latitude":
|
|
129
|
-
"longitude":
|
|
130
|
-
"wikidataQid": "
|
|
131
|
-
}
|
|
132
|
-
},
|
|
133
|
-
{
|
|
134
|
-
"slug": "shaheed-veer-narayan-singh-international-stadium",
|
|
135
|
-
"name": "Shaheed Veer Narayan Singh International Stadium",
|
|
136
|
-
"city": "Raipur",
|
|
137
|
-
"matchCount": 2,
|
|
138
|
-
"geo": {
|
|
139
|
-
"latitude": 21.2514,
|
|
140
|
-
"longitude": 81.6296,
|
|
141
|
-
"wikidataQid": "Q7461193"
|
|
142
|
-
}
|
|
143
|
-
}
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"slug": "narendra-modi-stadium",
|
|
4
|
+
"name": "Narendra Modi Stadium",
|
|
5
|
+
"city": "Ahmedabad",
|
|
6
|
+
"matchCount": 9,
|
|
7
|
+
"geo": {
|
|
8
|
+
"latitude": 23.0917,
|
|
9
|
+
"longitude": 72.5972,
|
|
10
|
+
"wikidataQid": "Q379935"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"slug": "wankhede-stadium",
|
|
15
|
+
"name": "Wankhede Stadium",
|
|
16
|
+
"city": "Mumbai",
|
|
17
|
+
"matchCount": 7,
|
|
18
|
+
"geo": {
|
|
19
|
+
"latitude": 18.9388,
|
|
20
|
+
"longitude": 72.8259,
|
|
21
|
+
"wikidataQid": "Q1067595"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"slug": "bharat-ratna-shri-atal-bihari-vajpayee-ekana-cricket-stadium",
|
|
26
|
+
"name": "Bharat Ratna Shri Atal Bihari Vajpayee Ekana Cricket Stadium",
|
|
27
|
+
"city": "Lucknow",
|
|
28
|
+
"matchCount": 7,
|
|
29
|
+
"geo": {
|
|
30
|
+
"latitude": 26.8467,
|
|
31
|
+
"longitude": 80.9462,
|
|
32
|
+
"wikidataQid": "Q26257057"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"slug": "arun-jaitley-stadium",
|
|
37
|
+
"name": "Arun Jaitley Stadium",
|
|
38
|
+
"city": "Delhi",
|
|
39
|
+
"matchCount": 7,
|
|
40
|
+
"geo": {
|
|
41
|
+
"latitude": 28.6379,
|
|
42
|
+
"longitude": 77.2425,
|
|
43
|
+
"wikidataQid": "Q582518"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"slug": "rajiv-gandhi-international-stadium",
|
|
48
|
+
"name": "Rajiv Gandhi International Stadium",
|
|
49
|
+
"city": "Hyderabad",
|
|
50
|
+
"matchCount": 7,
|
|
51
|
+
"geo": {
|
|
52
|
+
"latitude": 17.4068,
|
|
53
|
+
"longitude": 78.55,
|
|
54
|
+
"wikidataQid": "Q1419486"
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"slug": "maharaja-yadavindra-singh-international-cricket-stadium-mullanpu",
|
|
59
|
+
"name": "Maharaja Yadavindra Singh International Cricket Stadium, Mullanpur",
|
|
60
|
+
"city": "Chandigarh",
|
|
61
|
+
"matchCount": 6,
|
|
62
|
+
"geo": {
|
|
63
|
+
"latitude": 30.776,
|
|
64
|
+
"longitude": 76.7012
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"slug": "eden-gardens",
|
|
69
|
+
"name": "Eden Gardens",
|
|
70
|
+
"city": "Kolkata",
|
|
71
|
+
"matchCount": 6,
|
|
72
|
+
"geo": {
|
|
73
|
+
"latitude": 22.5645,
|
|
74
|
+
"longitude": 88.3433,
|
|
75
|
+
"wikidataQid": "Q582510"
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"slug": "ma-chidambaram-stadium",
|
|
80
|
+
"name": "MA Chidambaram Stadium",
|
|
81
|
+
"city": "Chennai",
|
|
82
|
+
"matchCount": 6,
|
|
83
|
+
"geo": {
|
|
84
|
+
"latitude": 13.0628,
|
|
85
|
+
"longitude": 80.2792,
|
|
86
|
+
"wikidataQid": "Q582488"
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"slug": "m-chinnaswamy-stadium",
|
|
91
|
+
"name": "M.Chinnaswamy Stadium",
|
|
92
|
+
"city": "Bengaluru",
|
|
93
|
+
"matchCount": 5,
|
|
94
|
+
"geo": {
|
|
95
|
+
"latitude": 12.9789,
|
|
96
|
+
"longitude": 77.5993,
|
|
97
|
+
"wikidataQid": "Q1135028"
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"slug": "sawai-mansingh-stadium",
|
|
102
|
+
"name": "Sawai Mansingh Stadium",
|
|
103
|
+
"city": "Jaipur",
|
|
104
|
+
"matchCount": 4,
|
|
105
|
+
"geo": {
|
|
106
|
+
"latitude": 26.8867,
|
|
107
|
+
"longitude": 75.8067,
|
|
108
|
+
"wikidataQid": "Q1437432"
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"slug": "himachal-pradesh-cricket-association-stadium",
|
|
113
|
+
"name": "Himachal Pradesh Cricket Association Stadium",
|
|
114
|
+
"city": "Dharamsala",
|
|
115
|
+
"matchCount": 4,
|
|
116
|
+
"geo": {
|
|
117
|
+
"latitude": 32.2393,
|
|
118
|
+
"longitude": 76.3186,
|
|
119
|
+
"wikidataQid": "Q5762830"
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"slug": "barsapara-cricket-stadium",
|
|
124
|
+
"name": "Barsapara Cricket Stadium",
|
|
125
|
+
"city": "Guwahati",
|
|
126
|
+
"matchCount": 3,
|
|
127
|
+
"geo": {
|
|
128
|
+
"latitude": 26.1305,
|
|
129
|
+
"longitude": 91.7966,
|
|
130
|
+
"wikidataQid": "Q24938094"
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"slug": "shaheed-veer-narayan-singh-international-stadium",
|
|
135
|
+
"name": "Shaheed Veer Narayan Singh International Stadium",
|
|
136
|
+
"city": "Raipur",
|
|
137
|
+
"matchCount": 2,
|
|
138
|
+
"geo": {
|
|
139
|
+
"latitude": 21.2514,
|
|
140
|
+
"longitude": 81.6296,
|
|
141
|
+
"wikidataQid": "Q7461193"
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
144
|
]
|
package/dist/index.js
CHANGED
|
@@ -163,6 +163,84 @@ function getMatches(limit) {
|
|
|
163
163
|
function getSeasonStats() {
|
|
164
164
|
return loadSeasonStats();
|
|
165
165
|
}
|
|
166
|
+
var _graphNodes = null;
|
|
167
|
+
var _graphOut = null;
|
|
168
|
+
var _graphIn = null;
|
|
169
|
+
function loadGraph() {
|
|
170
|
+
if (_graphNodes !== null) return;
|
|
171
|
+
_graphNodes = /* @__PURE__ */ new Map();
|
|
172
|
+
_graphOut = /* @__PURE__ */ new Map();
|
|
173
|
+
_graphIn = /* @__PURE__ */ new Map();
|
|
174
|
+
const doc = readJson("graph.json");
|
|
175
|
+
if (!doc) return;
|
|
176
|
+
for (const [slug, n] of Object.entries(doc.nodes ?? {})) {
|
|
177
|
+
_graphNodes.set(slug, { slug, type: n.type, name: n.name ?? null });
|
|
178
|
+
}
|
|
179
|
+
for (const e of doc.edges ?? []) {
|
|
180
|
+
if (!_graphOut.has(e.src)) _graphOut.set(e.src, []);
|
|
181
|
+
_graphOut.get(e.src).push(e);
|
|
182
|
+
if (!_graphIn.has(e.dst)) _graphIn.set(e.dst, []);
|
|
183
|
+
_graphIn.get(e.dst).push(e);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
function getGraphNode(slug) {
|
|
187
|
+
loadGraph();
|
|
188
|
+
return _graphNodes.get(slug) ?? null;
|
|
189
|
+
}
|
|
190
|
+
function graphEdges(slug, opts = {}) {
|
|
191
|
+
loadGraph();
|
|
192
|
+
const { predicate, direction = "out" } = opts;
|
|
193
|
+
const collected = [];
|
|
194
|
+
if (direction === "out" || direction === "both") collected.push(..._graphOut.get(slug) ?? []);
|
|
195
|
+
if (direction === "in" || direction === "both") collected.push(..._graphIn.get(slug) ?? []);
|
|
196
|
+
return predicate ? collected.filter((e) => e.predicate === predicate) : collected;
|
|
197
|
+
}
|
|
198
|
+
function graphRelated(slug, opts = {}) {
|
|
199
|
+
loadGraph();
|
|
200
|
+
const { predicate, direction = "out", limit = 25 } = opts;
|
|
201
|
+
const seen = /* @__PURE__ */ new Set();
|
|
202
|
+
const out = [];
|
|
203
|
+
const push = (otherSlug) => {
|
|
204
|
+
if (seen.has(otherSlug)) return;
|
|
205
|
+
const n = _graphNodes.get(otherSlug);
|
|
206
|
+
if (n) {
|
|
207
|
+
seen.add(otherSlug);
|
|
208
|
+
out.push(n);
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
if (direction === "out" || direction === "both") {
|
|
212
|
+
for (const e of _graphOut.get(slug) ?? []) if (!predicate || e.predicate === predicate) push(e.dst);
|
|
213
|
+
}
|
|
214
|
+
if (direction === "in" || direction === "both") {
|
|
215
|
+
for (const e of _graphIn.get(slug) ?? []) if (!predicate || e.predicate === predicate) push(e.src);
|
|
216
|
+
}
|
|
217
|
+
return out.slice(0, limit);
|
|
218
|
+
}
|
|
219
|
+
function graphPath(a, b, maxDepth = 4) {
|
|
220
|
+
loadGraph();
|
|
221
|
+
if (!_graphNodes.has(a) || !_graphNodes.has(b)) return null;
|
|
222
|
+
if (a === b) return [a];
|
|
223
|
+
const visited = /* @__PURE__ */ new Set([a]);
|
|
224
|
+
let frontier = [[a]];
|
|
225
|
+
for (let depth = 0; depth < maxDepth; depth++) {
|
|
226
|
+
const next = [];
|
|
227
|
+
for (const pathSoFar of frontier) {
|
|
228
|
+
const last = pathSoFar[pathSoFar.length - 1];
|
|
229
|
+
const nbrs = /* @__PURE__ */ new Set();
|
|
230
|
+
for (const e of _graphOut.get(last) ?? []) nbrs.add(e.dst);
|
|
231
|
+
for (const e of _graphIn.get(last) ?? []) nbrs.add(e.src);
|
|
232
|
+
for (const nb of nbrs) {
|
|
233
|
+
if (visited.has(nb)) continue;
|
|
234
|
+
const newPath = [...pathSoFar, nb];
|
|
235
|
+
if (nb === b) return newPath;
|
|
236
|
+
visited.add(nb);
|
|
237
|
+
next.push(newPath);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
frontier = next;
|
|
241
|
+
}
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
166
244
|
|
|
167
245
|
// src/tools/ipl-leaderboard.ts
|
|
168
246
|
var LEADERBOARD_ASPECTS = [
|
|
@@ -646,7 +724,7 @@ var TOOLS = [
|
|
|
646
724
|
},
|
|
647
725
|
{
|
|
648
726
|
name: "get_season_stats",
|
|
649
|
-
description: "IPL 2026 season leaderboard from
|
|
727
|
+
description: "IPL 2026 season leaderboard from CricketStudio canonical aggregate. sortBy: runs, wickets, strike_rate, economy, ducks, single_digit_outs, catches, run_outs. Optional teamCode filter. Sample-size floors apply (\u226530 balls faced for SR, \u226515 balls bowled for economy).",
|
|
650
728
|
inputSchema: { type: "object", properties: { sortBy: { type: "string", enum: ["runs", "wickets", "strike_rate", "economy", "ducks", "single_digit_outs", "catches", "run_outs"] }, teamCode: { type: "string", description: "Optional 2\u20134 letter team code e.g. MI, RCB" }, limit: { type: "number", description: "Max rows (default 15, max 100)" } }, required: ["sortBy"], additionalProperties: false }
|
|
651
729
|
},
|
|
652
730
|
{
|
|
@@ -716,7 +794,7 @@ var TOOLS = [
|
|
|
716
794
|
},
|
|
717
795
|
{
|
|
718
796
|
name: "get_fielding_stats",
|
|
719
|
-
description: "IPL 2026 fielding: catches, run-out assists, total dismissals. Pass playerSlug for a single player, omit for the full leaderboard. Aggregated from the
|
|
797
|
+
description: "IPL 2026 fielding: catches, run-out assists, total dismissals. Pass playerSlug for a single player, omit for the full leaderboard. Aggregated from the CricketStudio canonical snapshot.",
|
|
720
798
|
inputSchema: { type: "object", properties: { playerSlug: { type: "string", description: "Omit for leaderboard" }, limit: { type: "number", description: "Leaderboard rows (default 15)" } }, additionalProperties: false }
|
|
721
799
|
},
|
|
722
800
|
// ── GROUP 2: MLC ────────────────────────────────────────────────────
|
|
@@ -765,8 +843,25 @@ var TOOLS = [
|
|
|
765
843
|
name: "get_ipl_leaderboard",
|
|
766
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}.',
|
|
767
845
|
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
|
+
},
|
|
847
|
+
// ── GROUP 5: Knowledge graph (L3) ───────────────────────────────────
|
|
848
|
+
{
|
|
849
|
+
name: "get_related_entities",
|
|
850
|
+
description: 'Knowledge-graph traversal: entities connected to a player or franchise (by slug). Use for "who does Kohli play for", "which bowlers has Kohli faced", "who plays for RCB". Optional `predicate` filters the edge type (plays_for, faced, dismissed_by) and `direction` (out/in/both). Returns related entities + canonical URLs. Does NOT return per-ball detail \u2014 use get_player_h2h for one matchup. Matchup edges mirror the get_player_h2h pair set.',
|
|
851
|
+
inputSchema: { type: "object", properties: { slug: { type: "string", description: 'Entity slug, e.g. "virat-kohli" or "rcb"' }, predicate: { type: "string", enum: ["plays_for", "faced", "dismissed_by"] }, direction: { type: "string", enum: ["out", "in", "both"] }, limit: { type: "number", description: "Default 25, max 50" } }, required: ["slug"], additionalProperties: false }
|
|
852
|
+
},
|
|
853
|
+
{
|
|
854
|
+
name: "get_player_connections",
|
|
855
|
+
description: `A player's graph neighbourhood in one call: their franchise (plays_for), most-faced bowlers (by deliveries), and the bowlers who dismissed them most \u2014 each with canonical URLs + aggregate counts. Use for "who are Kohli's toughest bowlers", "which team does Kohli play for". Returns aggregates, not ball-by-ball. Matchup edges mirror the get_player_h2h pair set, so not every opponent appears.`,
|
|
856
|
+
inputSchema: { type: "object", properties: { playerSlug: { type: "string", description: "kebab-case slug e.g. virat-kohli" }, limit: { type: "number", description: "Default 10, max 50" } }, required: ["playerSlug"], additionalProperties: false }
|
|
857
|
+
},
|
|
858
|
+
{
|
|
859
|
+
name: "get_graph_path",
|
|
860
|
+
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
|
+
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 }
|
|
768
862
|
}
|
|
769
863
|
];
|
|
864
|
+
var GraphPredicates = ["plays_for", "faced", "dismissed_by"];
|
|
770
865
|
var validators = {
|
|
771
866
|
get_dataset_summary: z.object({}).strict(),
|
|
772
867
|
search_players: z.object({ query: z.string(), limit: z.number().optional() }).strict(),
|
|
@@ -796,7 +891,10 @@ var validators = {
|
|
|
796
891
|
get_mlc_match_claim: z.object({ matchId: z.string(), kind: z.enum(["top-batter", "top-bowler", "biggest-partnership", "pp-control", "death-domination"]) }).strict(),
|
|
797
892
|
list_mlc_matches: z.object({ season: z.string().optional(), teamSlug: z.string().optional(), limit: z.number().optional() }).strict(),
|
|
798
893
|
list_mlc_leaderboards: z.object({ aspect: z.string(), limit: z.number().optional() }).strict(),
|
|
799
|
-
get_ipl_leaderboard: z.object({ aspect: z.string(), season: z.string().optional(), limit: z.number().optional() }).strict()
|
|
894
|
+
get_ipl_leaderboard: z.object({ aspect: z.string(), season: z.string().optional(), limit: z.number().optional() }).strict(),
|
|
895
|
+
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
|
+
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()
|
|
800
898
|
};
|
|
801
899
|
function handleDatasetSummary() {
|
|
802
900
|
const md = metadata();
|
|
@@ -1226,7 +1324,7 @@ function handleListMlcLeaderboards(args) {
|
|
|
1226
1324
|
}
|
|
1227
1325
|
const limit = Math.max(1, Math.min(100, args.limit ?? 20));
|
|
1228
1326
|
const rows = Array.isArray(lb.rows) ? lb.rows : [];
|
|
1229
|
-
return ok({ aspect: lb.slug, title: lb.title, description: lb.description, metricLabel: lb.metricLabel, floorNote: lb.floorNote ?? null, count: Math.min(limit, rows.length), rows: rows.slice(0, limit).map((r) => ({ ...r, canonicalUrl: mlcPlayerUrl(r.slug) })), provenance: { source: "Cricsheet
|
|
1327
|
+
return ok({ aspect: lb.slug, title: lb.title, description: lb.description, metricLabel: lb.metricLabel, floorNote: lb.floorNote ?? null, count: Math.min(limit, rows.length), rows: rows.slice(0, limit).map((r) => ({ ...r, canonicalUrl: mlcPlayerUrl(r.slug) })), provenance: { source: "Cricsheet aggregate snapshot", license: "CC BY 3.0" } }, mlcLeaderboardUrl(lb.slug));
|
|
1230
1328
|
}
|
|
1231
1329
|
var IPL_LB_SPECS = {
|
|
1232
1330
|
// ── Batting aggregates ──────────────────────────────────────────────
|
|
@@ -1318,8 +1416,88 @@ function handleIplLeaderboard(args) {
|
|
|
1318
1416
|
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)" }
|
|
1319
1417
|
}, canonical);
|
|
1320
1418
|
}
|
|
1419
|
+
function urlForGraphNode(n) {
|
|
1420
|
+
switch (n.type) {
|
|
1421
|
+
case "player":
|
|
1422
|
+
return `${SITE}/players/${n.slug}`;
|
|
1423
|
+
case "franchise":
|
|
1424
|
+
return `${SITE}/teams/${n.slug}`;
|
|
1425
|
+
case "venue":
|
|
1426
|
+
return `${SITE}/venues/${n.slug}`;
|
|
1427
|
+
default:
|
|
1428
|
+
return null;
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
function projectGraphNode(n) {
|
|
1432
|
+
return { id: n.slug, type: n.type, name: n.name, canonical_url: urlForGraphNode(n) };
|
|
1433
|
+
}
|
|
1434
|
+
function handleGetRelatedEntities(args) {
|
|
1435
|
+
const slug = String(args.slug ?? "");
|
|
1436
|
+
const node = getGraphNode(slug);
|
|
1437
|
+
if (!node) return notFound(`No graph entity with slug "${slug}".`);
|
|
1438
|
+
const predicate = args.predicate ? String(args.predicate) : void 0;
|
|
1439
|
+
const direction = args.direction ?? "out";
|
|
1440
|
+
const limit = typeof args.limit === "number" ? Math.min(Math.max(args.limit, 1), 50) : 25;
|
|
1441
|
+
const related = graphRelated(slug, { predicate, direction, limit });
|
|
1442
|
+
return ok({
|
|
1443
|
+
entity: projectGraphNode(node),
|
|
1444
|
+
predicate: predicate ?? "all",
|
|
1445
|
+
direction,
|
|
1446
|
+
count: related.length,
|
|
1447
|
+
related: related.map(projectGraphNode),
|
|
1448
|
+
source: "CricketStudio knowledge graph (L3)"
|
|
1449
|
+
}, urlForGraphNode(node) ?? void 0);
|
|
1450
|
+
}
|
|
1451
|
+
function handleGetPlayerConnections(args) {
|
|
1452
|
+
const slug = String(args.playerSlug ?? "");
|
|
1453
|
+
const node = getGraphNode(slug);
|
|
1454
|
+
if (!node || node.type !== "player") return notFound(`No player in the graph with slug "${slug}".`);
|
|
1455
|
+
const limit = typeof args.limit === "number" ? Math.min(Math.max(args.limit, 1), 50) : 10;
|
|
1456
|
+
const playsFor = graphEdges(slug, { predicate: "plays_for", direction: "out" }).map((e) => getGraphNode(e.dst)).filter((n) => !!n).map(projectGraphNode);
|
|
1457
|
+
const mostFacedBowlers = graphEdges(slug, { predicate: "faced", direction: "out" }).slice().sort((a, b) => (b.props?.deliveries ?? 0) - (a.props?.deliveries ?? 0)).slice(0, limit).map((e) => {
|
|
1458
|
+
const n = getGraphNode(e.dst);
|
|
1459
|
+
return n ? { ...projectGraphNode(n), deliveries: e.props?.deliveries ?? 0, runs: e.props?.runs ?? 0, dismissals: e.props?.dismissals ?? 0 } : null;
|
|
1460
|
+
}).filter((x) => !!x);
|
|
1461
|
+
const dismissedByMost = graphEdges(slug, { predicate: "dismissed_by", direction: "out" }).slice().sort((a, b) => (b.props?.dismissals ?? 0) - (a.props?.dismissals ?? 0)).slice(0, limit).map((e) => {
|
|
1462
|
+
const n = getGraphNode(e.dst);
|
|
1463
|
+
return n ? { ...projectGraphNode(n), dismissals: e.props?.dismissals ?? 0 } : null;
|
|
1464
|
+
}).filter((x) => !!x);
|
|
1465
|
+
return ok({
|
|
1466
|
+
player: projectGraphNode(node),
|
|
1467
|
+
playsFor,
|
|
1468
|
+
mostFacedBowlers,
|
|
1469
|
+
dismissedByMost,
|
|
1470
|
+
window: "IPL career (faced/dismissed) + IPL 2026 (plays_for)",
|
|
1471
|
+
source: "CricketStudio knowledge graph (L3)",
|
|
1472
|
+
note: "Matchup edges mirror the get_player_h2h pair set; not every opponent is present."
|
|
1473
|
+
}, urlForGraphNode(node) ?? void 0);
|
|
1474
|
+
}
|
|
1475
|
+
function handleGetGraphPath(args) {
|
|
1476
|
+
const fromSlug = String(args.fromSlug ?? "");
|
|
1477
|
+
const toSlug = String(args.toSlug ?? "");
|
|
1478
|
+
const a = getGraphNode(fromSlug);
|
|
1479
|
+
if (!a) return notFound(`No graph entity with slug "${fromSlug}".`);
|
|
1480
|
+
const b = getGraphNode(toSlug);
|
|
1481
|
+
if (!b) return notFound(`No graph entity with slug "${toSlug}".`);
|
|
1482
|
+
const maxDepth = typeof args.maxDepth === "number" ? Math.min(Math.max(args.maxDepth, 1), 4) : 3;
|
|
1483
|
+
const ids = graphPath(fromSlug, toSlug, maxDepth);
|
|
1484
|
+
if (!ids) {
|
|
1485
|
+
return ok({ from: projectGraphNode(a), to: projectGraphNode(b), connected: false, path: [], note: `No connection within ${maxDepth} hops.`, source: "CricketStudio knowledge graph (L3)" });
|
|
1486
|
+
}
|
|
1487
|
+
return ok({
|
|
1488
|
+
from: projectGraphNode(a),
|
|
1489
|
+
to: projectGraphNode(b),
|
|
1490
|
+
connected: true,
|
|
1491
|
+
hops: ids.length - 1,
|
|
1492
|
+
path: ids.map((id) => {
|
|
1493
|
+
const n = getGraphNode(id);
|
|
1494
|
+
return n ? projectGraphNode(n) : { id, type: "unknown", name: null, canonical_url: null };
|
|
1495
|
+
}),
|
|
1496
|
+
source: "CricketStudio knowledge graph (L3)"
|
|
1497
|
+
});
|
|
1498
|
+
}
|
|
1321
1499
|
var server = new Server(
|
|
1322
|
-
{ name: "cricketstudio", version: "1.
|
|
1500
|
+
{ name: "cricketstudio", version: "1.1.0" },
|
|
1323
1501
|
{ capabilities: { tools: {} } }
|
|
1324
1502
|
);
|
|
1325
1503
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
|
|
@@ -1390,6 +1568,12 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
1390
1568
|
return handleListMlcLeaderboards(args);
|
|
1391
1569
|
case "get_ipl_leaderboard":
|
|
1392
1570
|
return handleIplLeaderboard(args);
|
|
1571
|
+
case "get_related_entities":
|
|
1572
|
+
return handleGetRelatedEntities(args);
|
|
1573
|
+
case "get_player_connections":
|
|
1574
|
+
return handleGetPlayerConnections(args);
|
|
1575
|
+
case "get_graph_path":
|
|
1576
|
+
return handleGetGraphPath(args);
|
|
1393
1577
|
default:
|
|
1394
1578
|
return ok({ error: "unknown_tool", tool: name });
|
|
1395
1579
|
}
|
package/package.json
CHANGED
|
@@ -1,55 +1,56 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "cricketstudio-mcp",
|
|
3
|
-
"version": "1.0
|
|
4
|
-
"description": "CricketStudio MCP server —
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "dist/index.js",
|
|
7
|
-
"bin": {
|
|
8
|
-
"cricketstudio-mcp": "dist/index.js"
|
|
9
|
-
},
|
|
10
|
-
"scripts": {
|
|
11
|
-
"build": "esbuild src/index.ts --bundle --platform=node --target=node18 --outfile=dist/index.js --format=esm --packages=external",
|
|
12
|
-
"dev": "tsx src/index.ts",
|
|
13
|
-
"typecheck": "tsc --noEmit",
|
|
14
|
-
"prepare": "npm run build",
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"ipl
|
|
22
|
-
"ipl-
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
|
|
32
|
-
"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
"dependencies": {
|
|
41
|
-
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
42
|
-
"zod": "^3.0.0"
|
|
43
|
-
},
|
|
44
|
-
"devDependencies": {
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
|
|
55
|
-
|
|
1
|
+
{
|
|
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.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"cricketstudio-mcp": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "esbuild src/index.ts --bundle --platform=node --target=node18 --outfile=dist/index.js --format=esm --packages=external",
|
|
12
|
+
"dev": "tsx src/index.ts",
|
|
13
|
+
"typecheck": "tsc --noEmit",
|
|
14
|
+
"prepare": "npm run build",
|
|
15
|
+
"smoke": "node scripts/smoke-test.mjs",
|
|
16
|
+
"validate": "node scripts/validate-snapshot.mjs"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"mcp",
|
|
20
|
+
"cricket",
|
|
21
|
+
"ipl",
|
|
22
|
+
"ipl-2026",
|
|
23
|
+
"ipl-historical",
|
|
24
|
+
"mlc",
|
|
25
|
+
"cricketstudio",
|
|
26
|
+
"claude",
|
|
27
|
+
"model-context-protocol"
|
|
28
|
+
],
|
|
29
|
+
"author": "Arul Anand / CricketStudio <hello@cricketstudio.ai>",
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "git+https://github.com/i-m-arul/cricketstudio-mcp.git"
|
|
34
|
+
},
|
|
35
|
+
"homepage": "https://players.cricketstudio.ai/mcp",
|
|
36
|
+
"mcpName": "io.github.i-m-arul/cricketstudio-mcp",
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">=18"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
42
|
+
"zod": "^3.0.0"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/node": "^22.19.21",
|
|
46
|
+
"esbuild": "^0.28.0",
|
|
47
|
+
"tsx": "^4.0.0",
|
|
48
|
+
"typescript": "^5.0.0"
|
|
49
|
+
},
|
|
50
|
+
"files": [
|
|
51
|
+
"dist/",
|
|
52
|
+
"data/snapshot/",
|
|
53
|
+
"README.md",
|
|
54
|
+
"LICENSE"
|
|
55
|
+
]
|
|
56
|
+
}
|