cito-mcp 0.5.6 → 0.5.8

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/README.md CHANGED
@@ -550,6 +550,14 @@ claude mcp add cito -e CITO_API_KEY=cito_… "--" npx -y cito-mcp
550
550
 
551
551
  ## Changelog (summary)
552
552
 
553
+ ### 0.5.8
554
+
555
+ - Tennis `player_rankings_history` asks `/tennis/rankings/history/{id}` for one page (`limit`, new `page`, `since` sent as `from`) instead of downloading the whole career and slicing it; page 1 is the newest `limit` rows, returned oldest-first as before. `omittedOlder` counts rows at the old end, new `omittedNewer` the rows on earlier (newer) pages, `hasMore` is the route's own `has_next`.
556
+
557
+ ### 0.5.7
558
+
559
+ - Tennis `event_card`: `event.drawSize` and `draw.drawSize` are the API's stored draw size, the same value `/tennis/tournaments/{id}` serves (it is now corrected to the proven size: Paris 56, Shanghai 96). `drawSizeVerified` says a proof stands behind it; `draw.drawSizeDerived` is what the edition's own bracket shows.
560
+
553
561
  ### 0.5.6
554
562
 
555
563
  - **Tennis `event_card` draw is a real bracket** (customer audit 2026-11-03). `draw.complete` is true only when every main round to the Final is played (it said true beside `missingRounds` F/SF/QF); every main round is listed with `status` (`completed` / `in_progress` / `not_started` / `incomplete_archive`), `expected` (byes excluded: a 56 draw's R64 holds 24), `byes`, `walkovers`, and `pending` (scheduled / live matches, never presented as results). `drawSize` is the real field (Paris 56, `drawSizeSource`, `bracketSize`, `byes`); `matchesExpected` counts the main draw and is compared with `mainDrawMatchesReturned` (qualifying is reported apart). Each bout carries `winnerId` / `loserId` / `outcome` (a "6-3 6-7 RET" retirement says who won), `startTime`, `nextMatchId` (the bracket edge) and `bracketPosition`; rounds report `included` / `omitted` when `drawMaxMatches` trims them.
@@ -1230,6 +1230,7 @@ Example: { "game": "ufc", "eventIdOrSlug": "ufc-300", "includeMatches": true, "i
1230
1230
  tier: pickString(d.tier) ?? null,
1231
1231
  surface: pickString(d.surface) ?? null,
1232
1232
  drawSize: typeof d.draw_size === 'number' ? d.draw_size : null,
1233
+ drawSizeVerified: typeof d.draw_size_verified === 'boolean' ? d.draw_size_verified : null,
1233
1234
  city: pickString(d.city) ?? null,
1234
1235
  country: pickString(d.country_code) ?? null,
1235
1236
  editions: { first: d.first_edition_year ?? null, mostRecent: d.most_recent_edition_year ?? null },
@@ -1397,6 +1398,8 @@ Example: { "game": "ufc", "eventIdOrSlug": "ufc-300", "includeMatches": true, "i
1397
1398
  drawSummary = {
1398
1399
  drawSize,
1399
1400
  drawSizeSource: pickString(dd.draw_size_source) ?? null,
1401
+ drawSizeVerified: typeof dd.draw_size_verified === 'boolean' ? dd.draw_size_verified : null,
1402
+ drawSizeDerived: num(dd.draw_size_derived),
1400
1403
  bracketSize: num(dd.bracket_size),
1401
1404
  byes: num(dd.byes),
1402
1405
  roundCount: drawRounds.length,
@@ -256,10 +256,11 @@ Prefer over: standings (latest snapshot only); rankings_movers (week-over-week d
256
256
  Do not use when: the current top-N table → standings with game tennis.
257
257
 
258
258
  Tennis-only. Rows arrive oldest-first (chronological), which is the order a chart
259
- wants; the newest entries are the tail. limit keeps the most RECENT N rows (the
260
- route itself ignores ?limit=, so the bound is applied here) — hasMore and
261
- oldestReturned/newestReturned say exactly which window came back, and
262
- omittedOlder counts the rows left behind at the old end.
259
+ wants; the newest entries are the tail. limit + page walk the series from the most
260
+ RECENT end (page 1 = the newest limit rows, page 2 the ones before them); the route
261
+ pages itself. hasMore and oldestReturned/newestReturned say exactly which window came
262
+ back, omittedOlder counts the rows left at the old end and omittedNewer the rows on
263
+ earlier (newer) pages.
263
264
 
264
265
  Parallel-safe: yes. Upstream cost: 1.`,
265
266
  inputSchema: {
@@ -271,6 +272,7 @@ Parallel-safe: yes. Upstream cost: 1.`,
271
272
  playerId: stringSchema('Tennis player id, e.g. "atp_207989" or "wta_214544".', 'atp_207989'),
272
273
  since: stringSchema('Only rows on or after this date (YYYY-MM-DD).', '2026-01-01'),
273
274
  limit: limitSchema({ default: 20, max: 500, description: 'Max history rows (default 20, max 500).' }),
275
+ page: { type: 'integer', minimum: 1, default: 1, description: 'Page from the newest end (1 = the most recent limit rows).' },
274
276
  },
275
277
  },
276
278
  handler: async (args, ctx) => {
@@ -323,8 +325,9 @@ Parallel-safe: yes. Upstream cost: 1.`,
323
325
  });
324
326
  }
325
327
  const limit = clampInt(args.limit, 20, 1, 500);
328
+ const page = clampInt(args.page, 1, 1, 100000);
326
329
  const res = await fetchJson(ctx, `/tennis/rankings/history/${encodeURIComponent(playerId)}`, {
327
- query: { limit },
330
+ query: { limit, page, ...(sinceRaw ? { from: sinceRaw } : {}) },
328
331
  });
329
332
  if (!res.ok) {
330
333
  return errorEnvelope({
@@ -354,8 +357,21 @@ Parallel-safe: yes. Upstream cost: 1.`,
354
357
  const inWindow = sinceRaw
355
358
  ? allHistory.filter((h) => h.date !== null && h.date >= sinceRaw)
356
359
  : allHistory;
357
- const total = inWindow.length;
358
- const history = total > limit ? inWindow.slice(total - limit) : inWindow;
360
+ const pagedUpstream = typeof body.total === 'number' && typeof body.order === 'string';
361
+ let total;
362
+ let history;
363
+ if (pagedUpstream) {
364
+ total = body.total;
365
+ history = body.order === 'desc' ? [...inWindow].reverse() : inWindow;
366
+ }
367
+ else {
368
+ total = inWindow.length;
369
+ const end = Math.max(0, total - (page - 1) * limit);
370
+ history = inWindow.slice(Math.max(0, end - limit), end);
371
+ }
372
+ const omittedNewer = Math.min(total, (page - 1) * limit);
373
+ const omittedOlder = Math.max(0, total - omittedNewer - history.length);
374
+ const hasMore = pagedUpstream && typeof body.has_next === 'boolean' ? body.has_next : omittedOlder > 0;
359
375
  const best = history.reduce((acc, h) => {
360
376
  if (h.rank === null)
361
377
  return acc;
@@ -366,9 +382,9 @@ Parallel-safe: yes. Upstream cost: 1.`,
366
382
  return successEnvelope({
367
383
  pagination: {
368
384
  limit,
369
- offset: total - history.length,
385
+ offset: omittedNewer,
370
386
  total,
371
- hasMore: total > history.length,
387
+ hasMore,
372
388
  nextCursor: null,
373
389
  prevCursor: null,
374
390
  },
@@ -391,7 +407,9 @@ Parallel-safe: yes. Upstream cost: 1.`,
391
407
  history,
392
408
  totalInWindow: total,
393
409
  returned: history.length,
394
- omittedOlder: total - history.length,
410
+ omittedOlder,
411
+ omittedNewer,
412
+ page,
395
413
  oldestReturned: history.length ? history[0].date : null,
396
414
  newestReturned: history.length ? history[history.length - 1].date : null,
397
415
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cito-mcp",
3
- "version": "0.5.6",
3
+ "version": "0.5.8",
4
4
  "description": "Standalone MCP server for the Cito esports and sports API — curated outcome tools for agents (live scoreboards, round economy, opening duels, clutches, vetoes, rosters, tennis, mma).",
5
5
  "type": "module",
6
6
  "homepage": "https://cito.gg",