Free NBA impact metrics: ARC, LOKI, game ratings, on/off, lineups, box scores. SQL + player tools.
Maintain this server? Claim it
Call this server's tools from your browser. Nothing to install.
Free LUMA API key (luma_sk_...), by email at https://lumahoops.org/developers#key
Requests go through mcptry because browsers can't call most MCP servers directly. Header values are sent to the server for that request only and are never stored or logged.
Tool list from our last check. Connect live to refresh it.
Side-by-side comparison of 2-6 players for one season. source: all (default: ARC net / O / D / SV / PV, the SV / PV tree, SV by zone, individual-skill view, PAC, xPTS-RAPM, skills, LOKI, on/off, box in one answer) | arc_season | arc_svpv | arc_zones | arc_skill | pac_season | xpts_rapm | skills_season | loki_release | onoff_season | box_season. window = ARC window, default 2.
Pick your client. Values in capitals, like YOUR_TOKEN, are yours to fill in.
Run in a terminal
claude mcp add --transport http luma https://lumahoops.org/api/mcp \ --header 'x-luma-key: YOUR_X_LUMA_KEY'
Headers
x-luma-key (required): Free LUMA API key (luma_sk_...), by email at https://lumahoops.org/developers#keySide-by-side comparison of 2-6 players for one season. source: all (default: ARC net / O / D / SV / PV, the SV / PV tree, SV by zone, individual-skill view, PAC, xPTS-RAPM, skills, LOKI, on/off, box in one answer) | arc_season | arc_svpv | arc_zones | arc_skill | pac_season | xpts_rapm | skills_season | loki_release | onoff_season | box_season. window = ARC window, default 2.
| Argument | Type | Description |
|---|---|---|
| season | integer | |
| source | string | |
| window | integer | |
| players* | array |
{
"type": "object",
"required": [
"players"
],
"properties": {
"season": {
"type": "integer"
},
"source": {
"enum": [
"all",
"arc_season",
"arc_svpv",
"arc_zones",
"arc_skill",
"pac_season",
"xpts_rapm",
"skills_season",
"onoff_season",
"box_season",
"loki_release"
],
"type": "string"
},
"window": {
"type": "integer"
},
"players": {
"type": "array",
"items": {
"type": "string"
},
"maxItems": 6,
"minItems": 2
}
},
"additionalProperties": false
}What a table, column or metric MEANS: definition, unit, which way is good, stability, flags. Pass a table (players, games, box_game, box_season, arc_season, arc_live, loki, loki_release, onoff_season, lineups, wowy, channels, xpts_rapm, player_seasons, pac_season, skills_season) or a metric id (e.g. sk_playmaking, ocreated, o_sel_rim, xq_d). Pass nothing for the conventions (units, seasons, sample sizes).
| Argument | Type | Description |
|---|---|---|
| table | string | |
| column | string | |
| metric | string |
{
"type": "object",
"properties": {
"table": {
"type": "string"
},
"column": {
"type": "string"
},
"metric": {
"type": "string"
}
},
"additionalProperties": false
}Map of the LUMA agent docs (agent-to-agent): house rules, what each model is, every column defined, how to read ARC, published test results, FAQ, and the public pages to read for more. Read once per session, before explaining any LUMA model to a user.
No arguments.
{
"type": "object",
"properties": {},
"additionalProperties": false
}Explain one LUMA term (e.g. "ARC", "LOKI", "shot value", "retention", "lineups", "Team FE", "cRAPM", "PAC", "p_top10"): the matching definitions from the agent docs plus any metric channels with that name. Use it when a user asks what something means.
| Argument | Type | Description |
|---|---|---|
| term* | string |
{
"type": "object",
"required": [
"term"
],
"properties": {
"term": {
"type": "string"
}
},
"additionalProperties": false
}Box-score game log for a player and season (regular season or playoffs). last_n limits to the most recent games.
| Argument | Type | Description |
|---|---|---|
| last_n | integer | |
| player* | string | |
| season | integer | |
| season_type | string |
{
"type": "object",
"required": [
"player"
],
"properties": {
"last_n": {
"type": "integer"
},
"player": {
"type": "string"
},
"season": {
"type": "integer"
},
"season_type": {
"enum": [
"regular",
"playoffs"
],
"type": "string"
}
},
"additionalProperties": false
}LUMA game ratings (the lumahoops.org/games page): every NBA regular-season game of 2025-26 and 2026-27, each player's Game ARC (points he added to his team's margin vs an average player in the same possessions), Game ARC per 100 possessions, the four ARC channels (shot value offense / defense, possession value gained / retained), the 0-10 game rating (6.6 = a typical game), PAC and his box score. level: players (default) or teams (team totals, average rating, channels). Filters: date (YYYY-MM-DD, or "latest" = the latest rated day; the default when no other filter is given), from, to, game_id, team, player (name), min_minutes. decomposition: true (players level) adds the full Game ARC decomposition: each channel split into its counted parts, shot parts by zone (rim, paint, mid, three) and free throws, attempts and makes per zone, plus one lineup number per channel; parts + lineup = the channel. Updated daily. Up to 5,000 rows per call; use offset for more.
| Argument | Type | Description |
|---|---|---|
| to | string | |
| date | string | |
| from | string | |
| team | string | |
| level | string | |
| limit | integer | |
| offset | integer |
Ranked list from one source. source: arc_season | arc_live | loki | loki_release | onoff_season | box_season | xpts_rapm | pac_season | skills_season (e.g. sk_switchability_pct) | channels (metric = a metric id from describe, e.g. sk_playmaking, ocreated, xq_d; window 1-5, LOKI channels have one value per season). metric must be a column of that source. Filters: season, window (arc_season 1-5), release (loki R1-R4, or weekly for the in-progress season; default R1, newest for the in-progress season), min_poss, pos (G/W/B), team, per (box_season: total|per_game).
| Argument | Type | Description |
|---|---|---|
| per | string | |
| pos | string | |
| team | string | |
| limit | integer | |
| metric | string | |
| season | integer | |
| source* | string | |
| window | integer | |
| release | string |
Lineup groups (2-5 players together) for a team-season, or the groups a player is in. size 2-5 (default 5). No possession minimum (default sort = possessions; use min_poss to filter). sort: poss | net | ortg | drtg.
| Argument | Type | Description |
|---|---|---|
| size | integer | |
| sort | string | |
| team | string | |
| limit | integer | |
| player | string | |
| season | integer | |
| min_poss | integer |
{
"type": "object",
"properties": {
"size": {
"type": "integer"
},
"sort": {
"enum": [
"poss",
"net",
"ortg",
"drtg"
],
"type": "string"
},
"team": {
"type": "string"
},
"limit": {
"type": "integer"
},
"player": {
"type": "string"
},
"season": {
"type": "integer"
},
"min_poss": {
"type": "integer"
}
},
"additionalProperties": false
}Raw on/off splits for a player across seasons: team ratings and shot diet with him on vs off (games he played) plus the NBA.com-style tenure version. Unadjusted -- depends on teammates and opponents. season = one season; or from_season / to_season. No possession minimum: check on_poss / off_poss.
| Argument | Type | Description |
|---|---|---|
| player* | string | |
| season | integer | |
| to_season | integer | |
| from_season | integer |
{
"type": "object",
"required": [
"player"
],
"properties": {
"player": {
"type": "string"
},
"season": {
"type": "integer"
},
"to_season": {
"type": "integer"
},
"from_season": {
"type": "integer"
}
},
"additionalProperties": false
}One-stop player profile for a season (owner 2026-10-25: show everything). ARC 2-season and 1-season (net, O, D, shot value SV, possession value PV), the full SV / PV tree (selection, conversion, retention, generation, O and D), SV by zone, ARC individual-skill view (a separate slicing of the same total), PAC, xPTS-RAPM, creation lens, top skills, LOKI, raw on/off, top WOWY partners, box score. Default season = the last full season until about the All-Star break of the season in progress (the response says so); pass season for the current one (2027 = 2026-27).
| Argument | Type | Description |
|---|---|---|
| player* | string | name or pid |
| season | integer | end year, e.g. 2026 = 2025-26 |
{
"type": "object",
"required": [
"player"
],
"properties": {
"player": {
"type": "string",
"description": "name or pid"
},
"season": {
"type": "integer",
"description": "end year, e.g. 2026 = 2025-26"
}
},
"additionalProperties": false
}Read one LUMA agent doc. ids: README, boundary, concepts, how-to-read-arc, metrics, validation, faq. boundary = house rules (read before quoting numbers); concepts = the models; metrics = every column; how-to-read-arc = what an ARC number means; validation = test results; faq.
| Argument | Type | Description |
|---|---|---|
| id* | string |
{
"type": "object",
"required": [
"id"
],
"properties": {
"id": {
"enum": [
"README",
"boundary",
"concepts",
"how-to-read-arc",
"metrics",
"validation",
"faq"
],
"type": "string"
}
},
"additionalProperties": false
}Read a public LUMA page as text (lumahoops.org), for when the agent docs point to a page: e.g. /luma/arc/about, /luma/loki/about, /luma/pac, /luma/rapm, /luma/wins, /luma/changelog, /luma/papers/pac-working-paper-v1.pdf, /luma/research/possession-by-possession-fundamentalism. Long pages come in chunks: pass offset to continue.
| Argument | Type | Description |
|---|---|---|
| url* | string | lumahoops.org URL or path |
| offset | integer |
{
"type": "object",
"required": [
"url"
],
"properties": {
"url": {
"type": "string",
"description": "lumahoops.org URL or path"
},
"offset": {
"type": "integer"
}
},
"additionalProperties": false
}Find players by (part of) name, accent-insensitive. Returns pid, name, first/last season, position group (G/W/B).
| Argument | Type | Description |
|---|---|---|
| limit | integer | |
| query* | string |
{
"type": "object",
"required": [
"query"
],
"properties": {
"limit": {
"type": "integer"
},
"query": {
"type": "string"
}
},
"additionalProperties": false
}Read-only SQL (DuckDB dialect) over the warehouse views: players, player_seasons (listed position / height by season), games, box_game, box_season, arc_season, arc_live, loki, loki_release, pac_season, skills_season (19 skill groups + season percentiles), onoff_season and lineups (incl. four factors and rebound shares), wowy, channels, xpts_rapm. One SELECT only, max 200 rows; PIVOT is not allowed (use max(x) filter (where ...)); quote "window" and "asof"; write every column alias with AS (a bare alias like load / value / rows / minutes is a syntax error). Use other tools first; call describe for column meanings.
| Argument | Type | Description |
|---|---|---|
| limit | integer | |
| query* | string |
{
"type": "object",
"required": [
"query"
],
"properties": {
"limit": {
"type": "integer"
},
"query": {
"type": "string"
}
},
"additionalProperties": false
}CALL THIS FIRST. Returns the LUMA guide (LUMA.md): every table and column, conventions (seasons, heights, positions, per-100, traded players), worked SQL recipes, what is NOT available, and the rules for crediting the data. Read it before writing sql.
No arguments.
{
"type": "object",
"properties": {},
"additionalProperties": false
}With-or-without-you for teammates in a team-season: team ratings with both on, only A, only B, neither. Give two players, or one player to list his partners. No possession minimum: check poss_together (small states are noise).
| Argument | Type | Description |
|---|---|---|
| with | string | |
| limit | integer | |
| player* | string | |
| season | integer |
{
"type": "object",
"required": [
"player"
],
"properties": {
"with": {
"type": "string"
},
"limit": {
"type": "integer"
},
"player": {
"type": "string"
},
"season": {
"type": "integer"
}
},
"additionalProperties": false
}We read every tool's name, description and inputs the way the model will, looking for instructions hidden from you. A clean result means no warning signs, not a guarantee. Scanned Nov 15, 2026.
| player | string |
| game_id | string |
| min_minutes | number |
| decomposition | boolean |
{
"type": "object",
"properties": {
"to": {
"type": "string"
},
"date": {
"type": "string"
},
"from": {
"type": "string"
},
"team": {
"type": "string"
},
"level": {
"enum": [
"players",
"teams"
],
"type": "string"
},
"limit": {
"type": "integer"
},
"offset": {
"type": "integer"
},
"player": {
"type": "string"
},
"game_id": {
"type": "string"
},
"min_minutes": {
"type": "number"
},
"decomposition": {
"type": "boolean"
}
},
"additionalProperties": false
}| min_poss | integer |
| ascending | boolean |
{
"type": "object",
"required": [
"source"
],
"properties": {
"per": {
"enum": [
"total",
"per_game"
],
"type": "string"
},
"pos": {
"type": "string"
},
"team": {
"type": "string"
},
"limit": {
"type": "integer"
},
"metric": {
"type": "string"
},
"season": {
"type": "integer"
},
"source": {
"enum": [
"arc_season",
"arc_live",
"loki_release",
"loki",
"onoff_season",
"box_season",
"xpts_rapm",
"pac_season",
"skills_season",
"channels"
],
"type": "string"
},
"window": {
"type": "integer"
},
"release": {
"type": "string"
},
"min_poss": {
"type": "integer"
},
"ascending": {
"type": "boolean"
}
},
"additionalProperties": false
}