livetennisapi-mcp
MCP server for the Live Tennis API — give Claude, Cursor and other LLM agents real-time tennis scores, players and fixtures for ATP, WTA, Challenger, ITF and juniors. Odds, rankings, match statistics, charting and model win-probability tools require the P
npm · fingerprint 11f4e16b14f58b53b3e9293e · repository · RSS
25tools
2recorded versions
57dtracked
changed since 4 Sep
What changed
Changed between 4 September 2026 and 28 October 2026 (first seen 2026-10-28 13:07 UTC)
23 descriptions rewritten, 1 schema or annotation change with the description left byte-identical, 1 tool added.
--- pinned/check_api_status +++ observed/check_api_status { "annotations": { "destructiveHint": false, - "description": "Check whether the Live Tennis API is reachable and which plan the configured key is on. Useful for diagnosing why other tools are refusing data.", + "description": "Check whether the Live Tennis API is reachable and which plan the configured key is on. Use it to find out why other tools are refusing data. Works with no key.", "execution": { "taskSupport": "forbidden" }, + "additionalProperties": false, "properties": {}, "type": "object" }, - "description": "Whether a key was supplied with this call.", + "description": "Whether a key was configured for this tool set.", "type": "boolean" }, "message": { - "description": "Human-readable summary. Identical to the text content, so either half can be used alone.", + "description": "Human-readable summary of the result, safe to relay to the user verbatim.", "type": "string" }, "ok": { - "description": "True when the call returned data. False for a tier wall, a missing or rejected key, or an empty result — all of which are normal states with a clear remedy, not failures.", + "description": "True when the request succeeded, including when the answer is an empty list. False for a missing or rejected key, a plan that does not include this data, an unknown id, a rate limit or a network error. The message then says what to do. check_api_status is the exception: it is true whenever the API answered, and reports API key problems in the message.", "type": "boolean" }, "reachable": {
--- pinned/get_archive_career +++ observed/get_archive_career { "annotations": { "destructiveHint": false, - "description": "One player's whole career over the results archive (1968–2022): W-L record overall and by surface/level/year, titles, and summed serve statistics with honest coverage — the corpus records serve stats from 1991 only, so matches_with_stats states how many matches the serve block covers. The name must resolve to one person; an ambiguous fragment returns the candidate list to choose from. Requires the BASIC plan or any History plan.", + "description": "One player's whole career over the results archive (1968 to 2022). W-L record in total and by surface/level/year, titles, and summed serve statistics. The corpus records serve stats from 1991 only, so matches_with_stats says how many matches the serve block covers. The name must resolve to one person. An ambiguous fragment returns the candidate list to choose from. Requires the BASIC plan or any History plan.", "execution": { "taskSupport": "forbidden" }, - "description": "Player name fragment, min 3 chars — must resolve to exactly one person.", + "description": "Player name fragment, min 3 chars. Must resolve to exactly one person.", "minLength": 3, "type": "string" } - "description": "Human-readable summary. Identical to the text content, so either half can be used alone.", + "description": "Human-readable summary of the result, safe to relay to the user verbatim.", "type": "string" }, "ok": { - "description": "True when the call returned data. False for a tier wall, a missing or rejected key, or an empty result — all of which are normal states with a clear remedy, not failures.", + "description": "True when the request succeeded, including when the answer is an empty list. False for a missing or rejected key, a plan that does not include this data, an unknown id, a rate limit or a network error. The message then says what to do. check_api_status is the exception: it is true whenever the API answered, and reports API key problems in the message.", "type": "boolean" }, "player_name": { - "description": "W-L per source tier code." + "description": "W-L per tier code." }, "by_surface": { "anyOf": [ - "description": "Summed serve stats + derived ratios. matches_with_stats states the coverage; ratios are null where the denominator is zero." + "description": "Summed serve stats + derived ratios. matches_with_stats states the coverage. Ratios are null where the denominator is zero." }, "span": { "additionalProperties": false,
--- pinned/get_archive_match +++ observed/get_archive_match { "annotations": { "destructiveHint": false, - "description": "One result from the results archive (1968–2022), with per-match serve statistics where the era recorded them — stats are null for most rows before 1991, honestly, never synthesised. Requires the BASIC plan or any History plan.", + "description": "One result from the results archive (1968 to 2022), with per-match serve statistics where the era recorded them. Stats are null for most rows before 1991, never synthesised. Requires the BASIC plan or any History plan.", "execution": { "taskSupport": "forbidden" }, - "description": "Human-readable summary. Identical to the text content, so either half can be used alone.", + "description": "Human-readable summary of the result, safe to relay to the user verbatim.", "type": "string" }, "ok": { - "description": "True when the call returned data. False for a tier wall, a missing or rejected key, or an empty result — all of which are normal states with a clear remedy, not failures.", + "description": "True when the request succeeded, including when the answer is an empty list. False for a missing or rejected key, a plan that does not include this data, an unknown id, a rate limit or a network error. The message then says what to do. check_api_status is the exception: it is true whenever the API answered, and reports API key problems in the message.", "type": "boolean" }, "result": { - "description": "The tournament START date — per-match dates do not exist in this era’s records.", + "description": "The tournament START date. Per-match dates do not exist in this era's records.", "type": [ "string", "null" - "description": "Source tier code: G, M, A, F, D, C, O, or a futures category code.", + "description": "Tier code: G, M, A, F, D, C, O, or a futures category code.", "type": [ "string", "null" - "description": "completed, retired, walkover, default or abandoned — parsed, null when unparseable.", + "description": "completed, retired, walkover, default or abandoned. Parsed, null when unparseable.", "type": [ "string", "null" - "description": "atp or wta — the results archive covers those two tours.", + "description": "atp or wta. The results archive covers those two tours.", "type": [ "string", "null" - "description": "The winner — a stored field in the corpus, never an inference.", + "description": "The winner, a stored field in the corpus, never an inference.", "properties": { "age": { "description": "Age at the time of the match.", - "description": "Draw entry where recorded (WC, Q, LL, …) — null for direct acceptances.", + "description": "Draw entry where recorded (WC, Q, LL, ...). Null for direct acceptances.", "type": [ "string", "null" - "description": "Corpus person id — pass to search_archive_players results to join bios. NOT a roster player id.", + "description": "Corpus person id. Join it to search_archive_players results for bios. NOT a roster player id.", "type": [ "number", "null"
--- pinned/get_charting_match +++ observed/get_charting_match { "annotations": { "destructiveHint": false, - "description": "Every Match Charting Project stat family for ONE charted match, both players, with the per-set split (set 1, set 2, …, Total) exactly as charted. Charting ids are their own id space (1960–2026), mostly matches with no counterpart in the live tables. Requires the ULTRA plan.", + "description": "Every charting stat family for ONE charted match, both players, with the per-set split (set 1, set 2, ..., Total) exactly as charted. Charting ids are their own id space (1960 to 2026). Most of these matches have no counterpart in the live tables. Requires the ULTRA plan.", "execution": { "taskSupport": "forbidden" }, - "description": "Charting match id — its own id space, not a match_id.", + "description": "Charting match id, in its own id space. Not a match_id.", "type": "integer" } }, - "description": "The Match Charting Project's own row identifier.", + "description": "The charting dataset's own row identifier.", "type": [ "string", "null" - "description": "Human-readable summary. Identical to the text content, so either half can be used alone.", + "description": "Human-readable summary of the result, safe to relay to the user verbatim.", "type": "string" }, "ok": { - "description": "True when the call returned data. False for a tier wall, a missing or rejected key, or an empty result — all of which are normal states with a clear remedy, not failures.", + "description": "True when the request succeeded, including when the answer is an empty list. False for a missing or rejected key, a plan that does not include this data, an unknown id, a rate limit or a network error. The message then says what to do. check_api_status is the exception: it is true whenever the API answered, and reports API key problems in the message.", "type": "boolean" }, "players": {
--- pinned/get_charting_player +++ observed/get_charting_player { "annotations": { "destructiveHint": false, - "description": "Career shot-level profile from the Match Charting Project: serve placement (deuce/ad × wide/body/T), return depth and outcomes, net play, clutch break/game/set-point serving, winners and errors by wing, rally-length tendencies — summed over the player's charted matches. COVERAGE IS CURATED (11,646 charted matches back to the 1960s, concentrated on the majors), not full-slate. An ambiguous name returns the candidates to choose from. Requires the ULTRA plan.", + "description": "Career profile from shot-level charting data, summed over the player's charted matches. Serve placement (deuce/ad x wide/body/T), return depth and outcomes, net play, and clutch break/game/set-point serving. Also winners and errors by wing, and rally-length tendencies. COVERAGE IS CURATED, not full-slate: 11,646 charted matches back to the 1960s, concentrated on the majors. An ambiguous name returns the candidates to choose from. Requires the ULTRA plan.", "execution": { "taskSupport": "forbidden" }, - "description": "Player name fragment, min 3 chars — must resolve to one charted person.", + "description": "Player name fragment, min 3 chars. Must resolve to one charted person.", "minLength": 3, "type": "string" } - "description": "Per-family summed numeric columns — raw sums over the player's charted Total rows.", + "description": "Per-family summed numeric columns: raw sums over the player's charted Total rows.", "type": "object" }, "matches_charted": { - "description": "Human-readable summary. Identical to the text content, so either half can be used alone.", + "description": "Human-readable summary of the result, safe to relay to the user verbatim.", "type": "string" }, "ok": { - "description": "True when the call returned data. False for a tier wall, a missing or rejected key, or an empty result — all of which are normal states with a clear remedy, not failures.", + "description": "True when the request succeeded, including when the answer is an empty list. False for a missing or rejected key, a plan that does not include this data, an unknown id, a rate limit or a network error. The message then says what to do. check_api_status is the exception: it is true whenever the API answered, and reports API key problems in the message.", "type": "boolean" }, "player": {
--- pinned/get_fixtures +++ observed/get_fixtures { "annotations": { "destructiveHint": false, - "description": "Upcoming scheduled tennis fixtures, earliest first — the forward schedule.", + "description": "Upcoming scheduled tennis fixtures, earliest first. This is the forward schedule, filterable by tour. Use this for \"what is on this week\". Works on the FREE plan (no card needed).", "execution": { "taskSupport": "forbidden" }, - "description": "Tour filter; each name covers its doubles variants. Exhibition/team events carry no tour and are excluded whenever the filter is used.", + "description": "Tour filter. Each name covers its doubles variants. Exhibition/team events carry no tour and are excluded whenever the filter is used.", "enum": [ "atp", "wta", - "description": "Scheduled start, ISO timestamp.", + "description": "Scheduled date, YYYY-MM-DD.", "type": [ "string", "null" + "start_time": { + "description": "Scheduled start, UTC ISO-8601. Null until the order of play assigns a time.", + "type": [ + "string", + "null" + ] + }, "tournament": { "description": "Event name.", "type": [ + "start_time", "tournament", "round", "player1", - "description": "Human-readable summary. Identical to the text content, so either half can be used alone.", + "description": "Human-readable summary of the result, safe to relay to the user verbatim.", "type": "string" }, "ok": { - "description": "True when the call returned data. False for a tier wall, a missing or rejected key, or an empty result — all of which are normal states with a clear remedy, not failures.", + "description": "True when the request succeeded, including when the answer is an empty list. False for a missing or rejected key, a plan that does not include this data, an unknown id, a rate limit or a network error. The message then says what to do. check_api_status is the exception: it is true whenever the API answered, and reports API key problems in the message.", "type": "boolean" } },
--- pinned/get_h2h +++ observed/get_h2h { "annotations": { "destructiveHint": false, - "description": "The all-time record between two players, across BOTH halves of the product: the results archive (1968–2022) plus our own completed matches (2023 onward). Names are the keys — an ambiguous fragment returns the candidate list to choose from rather than guessing. Totals count only meetings with a known winner; walkovers and retirements are part of the record and each meeting carries its outcome. Requires the BASIC plan or any History plan.", + "description": "The all-time record between two players, across BOTH halves of the product. That is the results archive (1968 to 2022) plus the completed matches from 2023 onward. Names are the keys. An ambiguous fragment returns the candidate list to choose from, and nothing is guessed. Totals count only meetings with a known winner. Walkovers and retirements are part of the record, and each meeting carries its outcome. Requires the BASIC plan or any History plan.", "execution": { "taskSupport": "forbidden" }, - "description": "Decided wins per surface; keys are surface names plus \"unknown\".", + "description": "Decided wins per surface. The keys are surface names plus \"unknown\".", "type": "object" }, "meetings": { - "description": "\"archive\" (results archive, 1968-2022) or \"current\" (our own completed matches, 2023 onward).", + "description": "\"archive\" (results archive, 1968-2022) or \"current\" (completed matches from 2023 onward).", "type": [ "string", "null" - "description": "Our match id (current era rows) — pass to get_match.", + "description": "Our match id (current era rows). Pass to get_match.", "type": [ "number", "null" - "description": "completed, retired, walkover, … — exclude non-completed yourself if needed.", + "description": "completed, retired, walkover, ... Exclude non-completed yourself if needed.", "type": [ "string", "null" - "description": "Final score (archive rows only — read current rows from get_match).", + "description": "Final score (archive rows only. Read current rows from get_match).", "type": [ "string", "null" - "description": "Human-readable summary. Identical to the text content, so either half can be used alone.", + "description": "Human-readable summary of the result, safe to relay to the user verbatim.", "type": "string" }, "ok": { - "description": "True when the call returned data. False for a tier wall, a missing or rejected key, or an empty result — all of which are normal states with a clear remedy, not failures.", + "description": "True when the request succeeded, including when the answer is an empty list. False for a missing or rejected key, a plan that does not include this data, an unknown id, a rate limit or a network error. The message then says what to do. check_api_status is the exception: it is true whenever the API answered, and reports API key problems in the message.", "type": "boolean" }, "players": { - "description": "The resolved names; null when no player matches the fragments." + "description": "The resolved names. Null when no player matches the fragments." }, "totals": { "additionalProperties": false, - "description": "Meetings with no derivable winner — never counted in wins.", + "description": "Meetings with no derivable winner. Never counted in wins.", "type": [ "number", "null"
--- pinned/get_live_matches +++ observed/get_live_matches { "annotations": { "destructiveHint": false, - "description": "List tennis matches currently in progress, with live scores. Covers ATP, WTA, Challenger, ITF and juniors. Use this for \"what tennis is on right now\".", + "description": "List tennis matches currently in progress, with live scores. Covers ATP, WTA, Challenger, ITF and juniors. Use this for \"what tennis is on right now\". Works on the FREE plan (no card needed).", "execution": { "taskSupport": "forbidden" }, - "description": "Either participant's country — the lowercase 3-letter IOC-style code the Player object returns (e.g. ned, sui, gre), NOT ISO-3166. Players with no recorded country never match.", + "description": "Either participant's country: the lowercase 3-letter IOC-style code the Player object returns (e.g. ned, sui, gre), NOT ISO-3166. Players with no recorded country never match.", "maxLength": 3, "minLength": 3, "type": "string" - "description": "Player ids (from search_players), max 50 — keeps matches where ANY listed player is either participant.", + "description": "Player ids (from search_players), max 50. Keeps matches where ANY listed player is either participant.", "items": { "type": "integer" }, - "description": "Tour filter; each name covers its doubles variants. Exhibition/team events carry no tour and are excluded whenever the filter is used.", + "description": "Tour filter. Each name covers its doubles variants. Exhibition/team events carry no tour and are excluded whenever the filter is used.", "enum": [ "atp", "wta", + "event_status_updated_at": { + "description": "The instant the current event_status was recorded, UTC ISO-8601 (added 2026-08-19). Null while the status has never changed since the field was introduced. Never backfilled.", + "type": [ + "string", + "null" + ] + }, + "has_analysis": { + "description": "Whether a model thesis or profile exists for this match (added 2026-09-02, every tier). Filter on this before calling get_match_analysis, which reports the same absence. Null only when the server predates the field.", + "type": [ + "boolean", + "null" + ] + }, + "has_market": { + "description": "Whether a match-winner market is mapped to this match (added 2026-09-02, every tier). Filter on this before calling get_match_odds, which reports the same absence. Null only when the server predates the field.", + "type": [ + "boolean", + "null" + ] + }, "id": { "description": "Match id. Pass to get_match, get_match_score, get_match_events or get_match_odds.", "type": [ - "description": "Round in the normalized vocabulary (F, SF, QF, R16 … Q); null when the label is unrecognised, never guessed.", + "description": "Round in the normalized vocabulary (F, SF, QF, R16 ... Q). Null when the label is unrecognised, never guessed.", "type": [ "string", "null" + "scheduled_time": { + "description": "Scheduled start, UTC ISO-8601. Null when no start time is set yet.", + "type": [ + "string", + "null" + ] + }, "score": { "description": "Formatted score line, e.g. \"6-4 3-6 2-1\".", "type": [ - "description": "One of live, upcoming or completed.", + "description": "One of live, upcoming, completed or cancelled.", "type": [ "string", "null" - "description": "atp, wta, challenger, itf or juniors. Null when the feed never stated one (exhibitions, team events).", + "description": "atp, wta, challenger, itf or juniors. Null when no tour is recorded (exhibitions, team events).", "type": [ "string", "null" - "description": "Stable tournament id — pass to get_tournament. Null where uncatalogued.", + "description": "Stable tournament id. Pass to get_tournament. Null where uncatalogued.", "type": [ "string", "null" - "description": "Model probability that player 1 wins, 0-1. Requires the ULTRA plan; null otherwise.", + "description": "Model probability that player 1 wins, 0-1. Requires the ULTRA plan, null otherwise.", "type": [ "number", "null" + "scheduled_time", "surface", "indoor", "serving", + "event_status_updated_at", "withdrew", + "has_analysis", + "has_market", "win_probability_p1" ], "type": "object" - "description": "Human-readable summary. Identical to the text content, so either half can be used alone.", + "description": "Human-readable summary of the result, safe to relay to the user verbatim.", "type": "string" }, "ok": { - "description": "True when the call returned data. False for a tier wall, a missing or rejected key, or an empty result — all of which are normal states with a clear remedy, not failures.", + "description": "True when the request succeeded, including when the answer is an empty list. False for a missing or rejected key, a plan that does not include this data, an unknown id, a rate limit or a network error. The message then says what to do. check_api_status is the exception: it is true whenever the API answered, and reports API key problems in the message.", "type": "boolean" } },
--- pinned/get_match +++ observed/get_match { "annotations": { "destructiveHint": false, - "description": "Full detail for one match by id: players, score, surface, round and status. Includes market prices on PRO and model analysis on ULTRA.", + "description": "Full detail for one match by id: players, score, surface, round and status. Includes market prices on PRO and model analysis on ULTRA. Works on the FREE plan (no card needed).", "execution": { "taskSupport": "forbidden" }, - "description": "Model analysis. Requires the ULTRA plan; absent otherwise.", + "description": "Model analysis. Requires the ULTRA plan, absent otherwise.", "properties": { "key_factors": { "description": "Drivers behind the model view.", - "description": "Match-winner market. Requires the PRO plan; absent otherwise.", + "description": "Match-winner market. Requires the PRO plan, absent otherwise.", "properties": { "prices": { "description": "Current prices per player.", + "event_status_updated_at": { + "description": "The instant the current event_status was recorded, UTC ISO-8601 (added 2026-08-19). Null while the status has never changed since the field was introduced. Never backfilled.", + "type": [ + "string", + "null" + ] + }, + "has_analysis": { + "description": "Whether a model thesis or profile exists for this match (added 2026-09-02, every tier). Filter on this before calling get_match_analysis, which reports the same absence. Null only when the server predates the field.", + "type": [ + "boolean", + "null" + ] + }, + "has_market": { + "description": "Whether a match-winner market is mapped to this match (added 2026-09-02, every tier). Filter on this before calling get_match_odds, which reports the same absence. Null only when the server predates the field.", + "type": [ + "boolean", + "null" + ] + }, "id": { "description": "Match id. Pass to get_match, get_match_score, get_match_events or get_match_odds.", "type": [ - "description": "Round in the normalized vocabulary (F, SF, QF, R16 … Q); null when the label is unrecognised, never guessed.", + "description": "Round in the normalized vocabulary (F, SF, QF, R16 ... Q). Null when the label is unrecognised, never guessed.", "type": [ "string", "null" + "scheduled_time": { + "description": "Scheduled start, UTC ISO-8601. Null when no start time is set yet.", + "type": [ + "string", + "null" + ] + }, "score": { "description": "Formatted score line, e.g. \"6-4 3-6 2-1\".", "type": [ - "description": "One of live, upcoming or completed.", + "description": "One of live, upcoming, completed or cancelled.", "type": [ "string", "null" - "description": "atp, wta, challenger, itf or juniors. Null when the feed never stated one (exhibitions, team events).", + "description": "atp, wta, challenger, itf or juniors. Null when no tour is recorded (exhibitions, team events).", "type": [ "string", "null" - "description": "Stable tournament id — pass to get_tournament. Null where uncatalogued.", + "description": "Stable tournament id. Pass to get_tournament. Null where uncatalogued.", "type": [ "string", "null" - "description": "Model probability that player 1 wins, 0-1. Requires the ULTRA plan; null otherwise.", + "description": "Model probability that player 1 wins, 0-1. Requires the ULTRA plan, null otherwise.", "type": [ "number", "null" + "scheduled_time", "surface", "indoor", "serving", + "event_status_updated_at", "withdrew", + "has_analysis", + "has_market", "win_probability_p1" ], "type": "object" - "description": "Human-readable summary. Identical to the text content, so either half can be used alone.", + "description": "Human-readable summary of the result, safe to relay to the user verbatim.", "type": "string" }, "ok": { - "description": "True when the call returned data. False for a tier wall, a missing or rejected key, or an empty result — all of which are normal states with a clear remedy, not failures.", + "description": "True when the request succeeded, including when the answer is an empty list. False for a missing or rejected key, a plan that does not include this data, an unknown id, a rate limit or a network error. The message then says what to do. check_api_status is the exception: it is true whenever the API answered, and reports API key problems in the message.", "type": "boolean" } },
--- pinned/get_match_analysis +++ observed/get_match_analysis { "annotations": { "destructiveHint": false, - "description": "Model analysis for a match: predicted win probability, the model's thesis and the key factors behind it. Requires the ULTRA plan.", + "description": "Model analysis for a match: predicted win probability, the model's thesis and the main factors behind it. Requires the ULTRA plan. Match rows carry has_analysis, so check it first. A match with no thesis or profile has nothing to return.", "execution": { "taskSupport": "forbidden" }, - "description": "Human-readable summary. Identical to the text content, so either half can be used alone.", + "description": "Human-readable summary of the result, safe to relay to the user verbatim.", "type": "string" }, "ok": { - "description": "True when the call returned data. False for a tier wall, a missing or rejected key, or an empty result — all of which are normal states with a clear remedy, not failures.", + "description": "True when the request succeeded, including when the answer is an empty list. False for a missing or rejected key, a plan that does not include this data, an unknown id, a rate limit or a network error. The message then says what to do. check_api_status is the exception: it is true whenever the API answered, and reports API key problems in the message.", "type": "boolean" }, "profile": {
--- pinned/get_match_events +++ observed/get_match_events { "annotations": { "destructiveHint": false, - "description": "Timeline of events for a match — breaks, games won, sets won, momentum runs. Requires the PRO plan.", + "description": "Timeline of events for a match: breaks, games won, sets won, momentum runs. Requires the PRO plan.", "execution": { "taskSupport": "forbidden" }, - "description": "Events in chronological order.", + "description": "Events, newest first, as the API returns them.", "items": { "additionalProperties": false, "properties": { - "description": "Human-readable summary. Identical to the text content, so either half can be used alone.", + "description": "Human-readable summary of the result, safe to relay to the user verbatim.", "type": "string" }, "ok": { - "description": "True when the call returned data. False for a tier wall, a missing or rejected key, or an empty result — all of which are normal states with a clear remedy, not failures.", + "description": "True when the request succeeded, including when the answer is an empty list. False for a missing or rejected key, a plan that does not include this data, an unknown id, a rate limit or a network error. The message then says what to do. check_api_status is the exception: it is true whenever the API answered, and reports API key problems in the message.", "type": "boolean" } },
--- pinned/get_match_odds +++ observed/get_match_odds { "annotations": { "destructiveHint": false, - "description": "Match-winner market prices for a match — implied probability per player, with bid, ask and mid. Requires the PRO plan.", + "description": "Match-winner market prices for a match: implied probability per player, with bid, ask and mid. Requires the PRO plan. Match rows carry has_market, so check it first. A match with no market mapped has no prices to return.", "execution": { "taskSupport": "forbidden" }, - "description": "Human-readable summary. Identical to the text content, so either half can be used alone.", + "description": "Human-readable summary of the result, safe to relay to the user verbatim.", "type": "string" }, "ok": { - "description": "True when the call returned data. False for a tier wall, a missing or rejected key, or an empty result — all of which are normal states with a clear remedy, not failures.", + "description": "True when the request succeeded, including when the answer is an empty list. False for a missing or rejected key, a plan that does not include this data, an unknown id, a rate limit or a network error. The message then says what to do. check_api_status is the exception: it is true whenever the API answered, and reports API key problems in the message.", "type": "boolean" } },
--- pinned/get_match_score +++ observed/get_match_score { "annotations": { "destructiveHint": false, - "description": "Current score for one match — the fastest, lowest-latency read. Use this when you only need the score and already know the match id.", + "description": "Current score for one match. This is the fastest read, with the lowest latency. Use it when you only need the score and already know the match id. Works on the FREE plan (no card needed).", "execution": { "taskSupport": "forbidden" }, - "description": "Human-readable summary. Identical to the text content, so either half can be used alone.", + "description": "Human-readable summary of the result, safe to relay to the user verbatim.", "type": "string" }, "ok": { - "description": "True when the call returned data. False for a tier wall, a missing or rejected key, or an empty result — all of which are normal states with a clear remedy, not failures.", + "description": "True when the request succeeded, including when the answer is an empty list. False for a missing or rejected key, a plan that does not include this data, an unknown id, a rate limit or a network error. The message then says what to do. check_api_status is the exception: it is true whenever the API answered, and reports API key problems in the message.", "type": "boolean" }, "score": {
--- pinned/get_match_statistics +++ observed/get_match_statistics { "annotations": { "destructiveHint": false, - "description": "In-play (or final) statistics for one match, in TWO families kept deliberately separate: DERIVED is rebuilt from the point-by-point record (holds/breaks, break points, service/return points); MEASURED is counted upstream and includes what no point record can yield — aces, double faults, the serve split, winners/unforced errors. Measured coverage varies by tour; absent fields are omitted, never zero-filled. Requires the ULTRA plan.", + "description": "In-play (or final) statistics for one match, in TWO families kept separate on purpose. DERIVED is rebuilt from the point-by-point record (holds/breaks, break points, service/return points). MEASURED is counted per match. It includes what no point record can yield: aces, double faults, the serve split, winners/unforced errors. Measured coverage varies by tour. Absent fields are omitted, never zero-filled. Requires the ULTRA plan.", "execution": { "taskSupport": "forbidden" }, - "description": "Human-readable summary. Identical to the text content, so either half can be used alone.", + "description": "Human-readable summary of the result, safe to relay to the user verbatim.", "type": "string" }, "ok": { - "description": "True when the call returned data. False for a tier wall, a missing or rejected key, or an empty result — all of which are normal states with a clear remedy, not failures.", + "description": "True when the request succeeded, including when the answer is an empty list. False for a missing or rejected key, a plan that does not include this data, an unknown id, a rate limit or a network error. The message then says what to do. check_api_status is the exception: it is true whenever the API answered, and reports API key problems in the message.", "type": "boolean" }, "statistics": { - "description": "live | final | stale | none | diverged — summarises the response.", + "description": "live | final | stale | none | diverged. Summarises the response.", "type": [ "string", "null" - "description": "Per-family coverage/as_of/age. The two ages use DIFFERENT clocks (derived: against the newest score row; measured: wall clock) and must not be compared. On diverged the measured values are withheld and measured_divergence says why." + "description": "Per-family coverage/as_of/age. The two ages use DIFFERENT clocks (derived: against the newest score row, measured: wall clock) and must not be compared. On diverged the measured values are withheld and measured_divergence says why." }, "games_counted": { "description": "Games the derived family covers (tiebreaks excluded, counted separately).", - "description": "Counted upstream — aces, double_faults, the serve split, winners/unforced errors where covered. Absent fields are omitted, never zero-filled. Quantities named in both families are computed two different ways: a cross-check, not a duplication." + "description": "Counted per match: aces, double_faults, the serve split, winners/unforced errors where covered. Absent fields are omitted, never zero-filled. Quantities named in both families are computed two different ways: a cross-check, not a duplication." } }, "required": [ - "description": "Null when coverage is none — the match exists and holding nothing is the honest answer." + "description": "Null when coverage is none. The match exists, and holding nothing is the honest answer." } }, "required": [
--- pinned/get_player +++ observed/get_player { "annotations": { "destructiveHint": false, - "description": "One player's profile: ranking, country, handedness, date of birth and cached stats.", + "description": "One player's profile: ranking, country, handedness, date of birth and cached stats. Works on the FREE plan (no card needed).", "execution": { "taskSupport": "forbidden" }, - "description": "Human-readable summary. Identical to the text content, so either half can be used alone.", + "description": "Human-readable summary of the result, safe to relay to the user verbatim.", "type": "string" }, "ok": { - "description": "True when the call returned data. False for a tier wall, a missing or rejected key, or an empty result — all of which are normal states with a clear remedy, not failures.", + "description": "True when the request succeeded, including when the answer is an empty list. False for a missing or rejected key, a plan that does not include this data, an unknown id, a rate limit or a network error. The message then says what to do. check_api_status is the exception: it is true whenever the API answered, and reports API key problems in the message.", "type": "boolean" }, "player": {
--- pinned/get_player_rankings +++ observed/get_player_rankings { "annotations": { "destructiveHint": false, - "description": "Point-in-time ranking records for SPECIFIC players: per system, the newest record in force ON OR BEFORE as_of — never one dated after it. Every other ranking field in this API is the CURRENT value joined at read time; this is the historical answer. Systems are never collapsed: ATP/WTA and the ITF circuits carry rank+points, UTR a rating. ITF and UTR history begins 2026-07-29. Requires the ULTRA plan.", + "description": "Point-in-time ranking records for SPECIFIC players. Per system, the newest record in force ON OR BEFORE as_of, never one dated after it. Every other ranking field in this API is the CURRENT value joined at read time. This one is the historical answer. Systems are never collapsed: ATP/WTA and the ITF circuits carry rank+points, UTR a rating. ITF and UTR history begins 2026-07-29. Requires the ULTRA plan.", "execution": { "taskSupport": "forbidden" }, - "description": "YYYY-MM-DD — the record in force on this date. Omit for the latest known.", + "description": "YYYY-MM-DD. The record in force on this date. Omit for the latest known.", "type": "string" }, "player_ids": { - "description": "Human-readable summary. Identical to the text content, so either half can be used alone.", + "description": "Human-readable summary of the result, safe to relay to the user verbatim.", "type": "string" }, "ok": { - "description": "True when the call returned data. False for a tier wall, a missing or rejected key, or an empty result — all of which are normal states with a clear remedy, not failures.", + "description": "True when the request succeeded, including when the answer is an empty list. False for a missing or rejected key, a plan that does not include this data, an unknown id, a rate limit or a network error. The message then says what to do. check_api_status is the exception: it is true whenever the API answered, and reports API key problems in the message.", "type": "boolean" }, "rankings": { - "description": "Roster player id — null on listing rows for players outside our roster.", + "description": "Roster player id. Null on listing rows for players outside our roster.", "type": [ "number", "null" - "description": "Name as the ranking publisher printed it (listing rows).", + "description": "Player name as it appears in the ranking (listing rows).", "type": [ "string", "null" - "description": "Rank at the preceding snapshot week (ATP/WTA only; null elsewhere).", + "description": "Rank at the preceding snapshot week (ATP/WTA only, null elsewhere).", "type": [ "number", "null" - "description": "The circuit's own signed weekly movement (ITF systems only).", + "description": "Signed weekly rank movement (ITF systems only).", "type": [ "number", "null" - "description": "UTR only; null elsewhere.", + "description": "UTR only, null elsewhere.", "type": [ "number", "null"
--- pinned/get_rankings +++ observed/get_rankings { "annotations": { "destructiveHint": false, - "description": "The FULL published ranking table in rank order for one system — the newest week at or before as_of. Rows carry player_name as published and a null player_id for players outside our roster, so the table has no silent holes. ATP/WTA history runs deep; the ITF circuits begin 2026-07-29. For point-in-time records of SPECIFIC players use get_player_rankings. Requires the PRO plan.", + "description": "The FULL published ranking table in rank order for one system, from the newest week at or before as_of. Rows carry player_name as published and a null player_id for players outside our roster, so the table has no silent holes. ATP/WTA history runs deep. The ITF circuits begin 2026-07-29. For point-in-time records of SPECIFIC players use get_player_rankings. Requires the PRO plan.", "execution": { "taskSupport": "forbidden" }, - "description": "YYYY-MM-DD — serves the newest published week at or before this date. Omit for latest.", + "description": "YYYY-MM-DD. Serves the newest published week at or before this date. Omit for latest.", "type": "string" }, "limit": { - "description": "Ranking system to list. utr has no listing — it is a rating, not a ranking.", + "description": "Ranking system to list. utr has no listing, because it is a rating, not a ranking.", "enum": [ "atp", "wta", - "description": "Human-readable summary. Identical to the text content, so either half can be used alone.", + "description": "Human-readable summary of the result, safe to relay to the user verbatim.", "type": "string" }, "ok": { - "description": "True when the call returned data. False for a tier wall, a missing or rejected key, or an empty result — all of which are normal states with a clear remedy, not failures.", + "description": "True when the request succeeded, including when the answer is an empty list. False for a missing or rejected key, a plan that does not include this data, an unknown id, a rate limit or a network error. The message then says what to do. check_api_status is the exception: it is true whenever the API answered, and reports API key problems in the message.", "type": "boolean" }, "rankings": { - "description": "Roster player id — null on listing rows for players outside our roster.", + "description": "Roster player id. Null on listing rows for players outside our roster.", "type": [ "number", "null" - "description": "Name as the ranking publisher printed it (listing rows).", + "description": "Player name as it appears in the ranking (listing rows).", "type": [ "string", "null" - "description": "Rank at the preceding snapshot week (ATP/WTA only; null elsewhere).", + "description": "Rank at the preceding snapshot week (ATP/WTA only, null elsewhere).", "type": [ "number", "null" - "description": "The circuit's own signed weekly movement (ITF systems only).", + "description": "Signed weekly rank movement (ITF systems only).", "type": [ "number", "null" - "description": "UTR only; null elsewhere.", + "description": "UTR only, null elsewhere.", "type": [ "number", "null"
--- pinned/get_recent_results +++ observed/get_recent_results { "annotations": { "destructiveHint": false, - "description": "Either participant's country — the lowercase 3-letter IOC-style code the Player object returns (e.g. ned, sui, gre), NOT ISO-3166. Players with no recorded country never match.", + "description": "Either participant's country: the lowercase 3-letter IOC-style code the Player object returns (e.g. ned, sui, gre), NOT ISO-3166. Players with no recorded country never match.", "maxLength": 3, "minLength": 3, "type": "string" - "description": "Player ids (from search_players), max 50 — keeps matches where ANY listed player is either participant.", + "description": "Player ids (from search_players), max 50. Keeps matches where ANY listed player is either participant.", "items": { "type": "integer" }, - "description": "Latest play date: YYYY-MM-DD or ISO-8601; must not precede from.", + "description": "Latest play date: YYYY-MM-DD or ISO-8601. Must not precede from.", "type": "string" }, "tour": { - "description": "Tour filter; each name covers its doubles variants. Exhibition/team events carry no tour and are excluded whenever the filter is used.", + "description": "Tour filter. Each name covers its doubles variants. Exhibition/team events carry no tour and are excluded whenever the filter is used.", "enum": [ "atp", "wta", + "event_status_updated_at": { + "description": "The instant the current event_status was recorded, UTC ISO-8601 (added 2026-08-19). Null while the status has never changed since the field was introduced. Never backfilled.", + "type": [ + "string", + "null" + ] + }, + "has_analysis": { + "description": "Whether a model thesis or profile exists for this match (added 2026-09-02, every tier). Filter on this before calling get_match_analysis, which reports the same absence. Null only when the server predates the field.", + "type": [ + "boolean", + "null" + ] + }, + "has_market": { + "description": "Whether a match-winner market is mapped to this match (added 2026-09-02, every tier). Filter on this before calling get_match_odds, which reports the same absence. Null only when the server predates the field.", + "type": [ + "boolean", + "null" + ] + }, "id": { "description": "Match id. Pass to get_match, get_match_score, get_match_events or get_match_odds.", "type": [ - "description": "Round in the normalized vocabulary (F, SF, QF, R16 … Q); null when the label is unrecognised, never guessed.", + "description": "Round in the normalized vocabulary (F, SF, QF, R16 ... Q). Null when the label is unrecognised, never guessed.", "type": [ "string", "null" + "scheduled_time": { + "description": "Scheduled start, UTC ISO-8601. Null when no start time is set yet.", + "type": [ + "string", + "null" + ] + }, "score": { "description": "Formatted score line, e.g. \"6-4 3-6 2-1\".", "type": [ - "description": "One of live, upcoming or completed.", + "description": "One of live, upcoming, completed or cancelled.", "type": [ "string", "null" - "description": "atp, wta, challenger, itf or juniors. Null when the feed never stated one (exhibitions, team events).", + "description": "atp, wta, challenger, itf or juniors. Null when no tour is recorded (exhibitions, team events).", "type": [ "string", "null" - "description": "Stable tournament id — pass to get_tournament. Null where uncatalogued.", + "description": "Stable tournament id. Pass to get_tournament. Null where uncatalogued.", "type": [ "string", "null" - "description": "Model probability that player 1 wins, 0-1. Requires the ULTRA plan; null otherwise.", + "description": "Model probability that player 1 wins, 0-1. Requires the ULTRA plan, null otherwise.", "type": [ "number", "null" + "scheduled_time", "surface", "indoor", "serving", + "event_status_updated_at", "withdrew", + "has_analysis", + "has_market", "win_probability_p1" ], "type": "object" - "description": "Human-readable summary. Identical to the text content, so either half can be used alone.", + "description": "Human-readable summary of the result, safe to relay to the user verbatim.", "type": "string" }, "ok": { - "description": "True when the call returned data. False for a tier wall, a missing or rejected key, or an empty result — all of which are normal states with a clear remedy, not failures.", + "description": "True when the request succeeded, including when the answer is an empty list. False for a missing or rejected key, a plan that does not include this data, an unknown id, a rate limit or a network error. The message then says what to do. check_api_status is the exception: it is true whenever the API answered, and reports API key problems in the message.", "type": "boolean" } },
--- pinned/get_tournament +++ observed/get_tournament { "annotations": { "destructiveHint": false, - "description": "One tournament by its stable id — the tournament_id carried on match objects. Name, tour, surface, indoor, plus host city/country and category where curated.", + "description": "One tournament by its stable id, the tournament_id carried on match objects. Name, tour, surface, indoor, plus host city/country and category where curated. Works on the FREE plan (no card needed).", "execution": { "taskSupport": "forbidden" }, - "description": "Human-readable summary. Identical to the text content, so either half can be used alone.", + "description": "Human-readable summary of the result, safe to relay to the user verbatim.", "type": "string" }, "ok": { - "description": "True when the call returned data. False for a tier wall, a missing or rejected key, or an empty result — all of which are normal states with a clear remedy, not failures.", + "description": "True when the request succeeded, including when the answer is an empty list. False for a missing or rejected key, a plan that does not include this data, an unknown id, a rate limit or a network error. The message then says what to do. check_api_status is the exception: it is true whenever the API answered, and reports API key problems in the message.", "type": "boolean" }, "tournament": { - "description": "Tournament category (grand_slam, masters_1000, tour_finals, atp_500, atp_250, wta_1000, wta_500, wta_250, wta_125, challenger, itf, juniors). Set only where the catalogues agree unambiguously — null otherwise, never derived from the name.", + "description": "Tournament category (grand_slam, masters_1000, tour_finals, atp_500, atp_250, wta_1000, wta_500, wta_250, wta_125, challenger, itf, juniors). Set only where the category is unambiguous. Null otherwise, never derived from the name.", "type": [ "string", "null" - "description": "Host city, from a curated table — null where not curated.", + "description": "Host city, from a curated table. Null where not curated.", "type": [ "string", "null" - "description": "Host country, ISO-3166 alpha-2 — null where not curated.", + "description": "Host country, ISO-3166 alpha-2. Null where not curated.", "type": [ "string", "null" - "description": "Stable tournament id — the same id match objects carry as tournament_id.", + "description": "Stable tournament id, the same id match objects carry as tournament_id.", "type": [ "string", "null"
--- pinned/get_upcoming_matches +++ observed/get_upcoming_matches { "annotations": { "destructiveHint": false, - "description": "List tennis matches scheduled to start soon, with players and tournament.", + "description": "List tennis matches scheduled to start soon, with players, tournament and start time. Use this for \"who plays next\" or to find a match id before it starts. Works on the FREE plan (no card needed).", "execution": { "taskSupport": "forbidden" }, - "description": "Either participant's country — the lowercase 3-letter IOC-style code the Player object returns (e.g. ned, sui, gre), NOT ISO-3166. Players with no recorded country never match.", + "description": "Either participant's country: the lowercase 3-letter IOC-style code the Player object returns (e.g. ned, sui, gre), NOT ISO-3166. Players with no recorded country never match.", "maxLength": 3, "minLength": 3, "type": "string" - "description": "Player ids (from search_players), max 50 — keeps matches where ANY listed player is either participant.", + "description": "Player ids (from search_players), max 50. Keeps matches where ANY listed player is either participant.", "items": { "type": "integer" }, - "description": "Latest play date: YYYY-MM-DD or ISO-8601; must not precede from.", + "description": "Latest play date: YYYY-MM-DD or ISO-8601. Must not precede from.", "type": "string" }, "tour": { - "description": "Tour filter; each name covers its doubles variants. Exhibition/team events carry no tour and are excluded whenever the filter is used.", + "description": "Tour filter. Each name covers its doubles variants. Exhibition/team events carry no tour and are excluded whenever the filter is used.", "enum": [ "atp", "wta", + "event_status_updated_at": { + "description": "The instant the current event_status was recorded, UTC ISO-8601 (added 2026-08-19). Null while the status has never changed since the field was introduced. Never backfilled.", + "type": [ + "string", + "null" + ] + }, + "has_analysis": { + "description": "Whether a model thesis or profile exists for this match (added 2026-09-02, every tier). Filter on this before calling get_match_analysis, which reports the same absence. Null only when the server predates the field.", + "type": [ + "boolean", + "null" + ] + }, + "has_market": { + "description": "Whether a match-winner market is mapped to this match (added 2026-09-02, every tier). Filter on this before calling get_match_odds, which reports the same absence. Null only when the server predates the field.", + "type": [ + "boolean", + "null" + ] + }, "id": { "description": "Match id. Pass to get_match, get_match_score, get_match_events or get_match_odds.", "type": [ - "description": "Round in the normalized vocabulary (F, SF, QF, R16 … Q); null when the label is unrecognised, never guessed.", + "description": "Round in the normalized vocabulary (F, SF, QF, R16 ... Q). Null when the label is unrecognised, never guessed.", "type": [ "string", "null" + "scheduled_time": { + "description": "Scheduled start, UTC ISO-8601. Null when no start time is set yet.", + "type": [ + "string", + "null" + ] + }, "score": { "description": "Formatted score line, e.g. \"6-4 3-6 2-1\".", "type": [ - "description": "One of live, upcoming or completed.", + "description": "One of live, upcoming, completed or cancelled.", "type": [ "string", "null" - "description": "atp, wta, challenger, itf or juniors. Null when the feed never stated one (exhibitions, team events).", + "description": "atp, wta, challenger, itf or juniors. Null when no tour is recorded (exhibitions, team events).", "type": [ "string", "null" - "description": "Stable tournament id — pass to get_tournament. Null where uncatalogued.", + "description": "Stable tournament id. Pass to get_tournament. Null where uncatalogued.", "type": [ "string", "null" - "description": "Model probability that player 1 wins, 0-1. Requires the ULTRA plan; null otherwise.", + "description": "Model probability that player 1 wins, 0-1. Requires the ULTRA plan, null otherwise.", "type": [ "number", "null" + "scheduled_time", "surface", "indoor", "serving", + "event_status_updated_at", "withdrew", + "has_analysis", + "has_market", "win_probability_p1" ], "type": "object" - "description": "Human-readable summary. Identical to the text content, so either half can be used alone.", + "description": "Human-readable summary of the result, safe to relay to the user verbatim.", "type": "string" }, "ok": { - "description": "True when the call returned data. False for a tier wall, a missing or rejected key, or an empty result — all of which are normal states with a clear remedy, not failures.", + "description": "True when the request succeeded, including when the answer is an empty list. False for a missing or rejected key, a plan that does not include this data, an unknown id, a rate limit or a network error. The message then says what to do. check_api_status is the exception: it is true whenever the API answered, and reports API key problems in the message.", "type": "boolean" } },
+ tool added: player_stats
--- pinned/search_archive_matches +++ observed/search_archive_matches { "annotations": { "destructiveHint": false, - "description": "Search the results archive — completed-match RESULTS from 1968 through 2022: ATP and WTA, main draws, qualifying and the ITF/futures tiers. Winner/loser-shaped records with final score, seeds and ranks AT THE TIME of the match. Use this for historical questions (\"Borg's Wimbledon finals\"); the archive ends 2022-12-31 where our own results (get_recent_results) begin. Requires the BASIC plan or any History plan.", + "description": "Search the results archive: completed-match RESULTS from 1968 through 2022. ATP and WTA, main draws, qualifying and the ITF/futures tiers. Each record has winner and loser, final score, and seeds and ranks AT THE TIME of the match. Use this for historical questions (\"Borg's Wimbledon finals\"). The archive ends 2022-12-31, where the current results (get_recent_results) begin. Requires the BASIC plan or any History plan.", "execution": { "taskSupport": "forbidden" }, - "description": "Source tier code: G=grand slam, M=masters, A=tour, F=finals, D=davis cup, C=challenger, O=olympics, or a futures category code (e.g. 15).", + "description": "Tier code: G=grand slam, M=masters, A=tour, F=finals, D=davis cup, C=challenger, O=olympics. Or a futures category code (e.g. 15).", "type": "string" }, "limit": { - "description": "Human-readable summary. Identical to the text content, so either half can be used alone.", + "description": "Human-readable summary of the result, safe to relay to the user verbatim.", "type": "string" }, "ok": { - "description": "True when the call returned data. False for a tier wall, a missing or rejected key, or an empty result — all of which are normal states with a clear remedy, not failures.", + "description": "True when the request succeeded, including when the answer is an empty list. False for a missing or rejected key, a plan that does not include this data, an unknown id, a rate limit or a network error. The message then says what to do. check_api_status is the exception: it is true whenever the API answered, and reports API key problems in the message.", "type": "boolean" }, "results": { - "description": "The tournament START date — per-match dates do not exist in this era’s records.", + "description": "The tournament START date. Per-match dates do not exist in this era's records.", "type": [ "string", "null" - "description": "Source tier code: G, M, A, F, D, C, O, or a futures category code.", + "description": "Tier code: G, M, A, F, D, C, O, or a futures category code.", "type": [ "string", "null" - "description": "completed, retired, walkover, default or abandoned — parsed, null when unparseable.", + "description": "completed, retired, walkover, default or abandoned. Parsed, null when unparseable.", "type": [ "string", "null" - "description": "atp or wta — the results archive covers those two tours.", + "description": "atp or wta. The results archive covers those two tours.", "type": [ "string", "null" - "description": "The winner — a stored field in the corpus, never an inference.", + "description": "The winner, a stored field in the corpus, never an inference.", "properties": { "age": { "description": "Age at the time of the match.", - "description": "Draw entry where recorded (WC, Q, LL, …) — null for direct acceptances.", + "description": "Draw entry where recorded (WC, Q, LL, ...). Null for direct acceptances.", "type": [ "string", "null" - "description": "Corpus person id — pass to search_archive_players results to join bios. NOT a roster player id.", + "description": "Corpus person id. Join it to search_archive_players results for bios. NOT a roster player id.", "type": [ "number", "null"
--- pinned/search_archive_players +++ observed/search_archive_players { "annotations": { "destructiveHint": false, - "description": "The people of the results archive (1968–2022): hand, date of birth, country, height, and career-high rank with the week it was first reached. Their ids are corpus person ids (the winner/loser player_id on archive results), not roster ids — for current players use search_players. Requires the BASIC plan or any History plan.", + "description": "The people of the results archive (1968 to 2022): hand, date of birth, country, height, and career-high rank with the week it was first reached. Their ids are corpus person ids (the winner/loser player_id on archive results), not roster ids. For current players use search_players. Requires the BASIC plan or any History plan.", "execution": { "taskSupport": "forbidden" }, - "description": "Human-readable summary. Identical to the text content, so either half can be used alone.", + "description": "Human-readable summary of the result, safe to relay to the user verbatim.", "type": "string" }, "ok": { - "description": "True when the call returned data. False for a tier wall, a missing or rejected key, or an empty result — all of which are normal states with a clear remedy, not failures.", + "description": "True when the request succeeded, including when the answer is an empty list. False for a missing or rejected key, a plan that does not include this data, an unknown id, a rate limit or a network error. The message then says what to do. check_api_status is the exception: it is true whenever the API answered, and reports API key problems in the message.", "type": "boolean" }, "players": { - "description": "Career-high rank, from the corpus’s own weekly tables.", + "description": "Career-high rank, from the archive's weekly ranking tables.", "type": [ "number", "null" - "description": "Corpus person id — the id archive match rows carry as winner/loser player_id. NOT a roster id.", + "description": "Corpus person id, the id archive match rows carry as winner/loser player_id. NOT a roster id.", "type": [ "number", "null"
--- pinned/search_players +++ observed/search_players { "annotations": { "destructiveHint": false, - "description": "Search tennis players by name. Returns id, country, ranking and tour. Use the returned id with get_player.", + "description": "Search tennis players by name. Returns id, country, ranking and tour. Use the returned id with get_player. Works on the FREE plan (no card needed).", "execution": { "taskSupport": "forbidden" }, - "description": "Human-readable summary. Identical to the text content, so either half can be used alone.", + "description": "Human-readable summary of the result, safe to relay to the user verbatim.", "type": "string" }, "ok": { - "description": "True when the call returned data. False for a tier wall, a missing or rejected key, or an empty result — all of which are normal states with a clear remedy, not failures.", + "description": "True when the request succeeded, including when the answer is an empty list. False for a missing or rejected key, a plan that does not include this data, an unknown id, a rate limit or a network error. The message then says what to do. check_api_status is the exception: it is true whenever the API answered, and reports API key problems in the message.", "type": "boolean" }, "players": {
--- pinned/search_tournaments +++ observed/search_tournaments { "annotations": { "destructiveHint": false, - "description": "Search the tournament catalogue — the stable id space that match objects carry as tournament_id. Returns surface, indoor, host city/country and category where curated.", + "description": "Search the tournament catalogue. Its ids are the tournament_id that match objects carry. Returns surface, indoor, host city/country and category where curated. Works on the FREE plan (no card needed).", "execution": { "taskSupport": "forbidden" }, - "description": "Human-readable summary. Identical to the text content, so either half can be used alone.", + "description": "Human-readable summary of the result, safe to relay to the user verbatim.", "type": "string" }, "ok": { - "description": "True when the call returned data. False for a tier wall, a missing or rejected key, or an empty result — all of which are normal states with a clear remedy, not failures.", + "description": "True when the request succeeded, including when the answer is an empty list. False for a missing or rejected key, a plan that does not include this data, an unknown id, a rate limit or a network error. The message then says what to do. check_api_status is the exception: it is true whenever the API answered, and reports API key problems in the message.", "type": "boolean" }, "tournaments": { - "description": "Tournament category (grand_slam, masters_1000, tour_finals, atp_500, atp_250, wta_1000, wta_500, wta_250, wta_125, challenger, itf, juniors). Set only where the catalogues agree unambiguously — null otherwise, never derived from the name.", + "description": "Tournament category (grand_slam, masters_1000, tour_finals, atp_500, atp_250, wta_1000, wta_500, wta_250, wta_125, challenger, itf, juniors). Set only where the category is unambiguous. Null otherwise, never derived from the name.", "type": [ "string", "null" - "description": "Host city, from a curated table — null where not curated.", + "description": "Host city, from a curated table. Null where not curated.", "type": [ "string", "null" - "description": "Host country, ISO-3166 alpha-2 — null where not curated.", + "description": "Host country, ISO-3166 alpha-2. Null where not curated.", "type": [ "string", "null" - "description": "Stable tournament id — the same id match objects carry as tournament_id.", + "description": "Stable tournament id, the same id match objects carry as tournament_id.", "type": [ "string", "null"
Current tools
Show all 25 tool fingerprints
check_api_status
get_archive_career
get_archive_match
get_charting_match
get_charting_player
get_fixtures
get_h2h
get_live_matches
get_match
get_match_analysis
get_match_events
get_match_odds
get_match_score
get_match_statistics
get_player
get_player_rankings
get_rankings
get_recent_results
get_tournament
get_upcoming_matches
player_stats
search_archive_matches
search_archive_players
search_players
search_tournaments
Watch this server yourself
If you run this server, put the proxy in front of it. It pins these exact fingerprints on first connect and stops the session if they move.
npx -y mcp-pin@0.2.3 -- <your livetennisapi-mcp command>
Or subscribe to this page's RSS feed to be told when it changes.
Badge
The badge states one fact about time and nothing else. It never claims a server is safe.
[](https://mcp-pin.gautamkhosla.com/servers/d5cec4de9b5bd9c0.html)