hockey-card-analyst
This server translates advanced hockey analytics card data into plain-language insights — all conclusions are strictly traceable to the numbers on the card.
Assess a player: Upload a skater or goalie card (standard, microstat, or both) for a full breakdown: overall tier, strengths, weaknesses, deployment context, trajectory, caveats, and a one-line summary.
Grade a claim: Submit a natural-language assertion (e.g. "he's an elite defender") and each claim is graded
supported,partial,not_supported, orunverifiable, with the specific card number cited as the receipt.Compare two players: Get a component-by-component comparison of two players within the same position pool, with an overall edge, an honest split when components genuinely divide, and a durability flag.
Explain a metric: Get a plain-language definition of any card metric (skater, goalie, or microstat) plus the single most important interpretive caveat — in the abstract, without rendering a verdict on a specific player.
Generate PDF reports: Download a styled PDF of any assessment, comparison, or claim-check result, saved locally. Supports skater/goalie/microstat assessments, head-to-head comparisons, graded claim checks, and "interpretive" reports (prominently badged as AI-generated) for free-form questions like line synergy.
Allows an NHL Edge page screenshot to be supplied alongside a player card for supplemental vetting, adding corroborations and contradictions between the card's verdicts and the league's tracking data without moving the tier.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@hockey-card-analystevaluate this player card"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Hockey Card Analyst
Turn an advanced hockey card into plain language you can say out loud and defend.
Hockey Card Analyst is a translator between advanced metrics and normal hockey conversation. It reads one analytics model's card for a player and tells you, in words, what the numbers actually say.
What it's for
Advanced player cards pack a lot into a small grid: a dozen percentiles, a couple of trend lines, and a headline number. The data is there, but reading it well means knowing the model underneath. What's repeatable versus lucky, what's a real skill versus an artifact of how a player is deployed, why a 95th percentile isn't the same as a 99th, why a defenseman's finishing doesn't count toward his value the way a forward's does. Most people looking at a card don't have that model in their head, so the numbers get half-read or misread.
This tool does the reading. Some of what it's useful for, drawn from real use:
Settling a claim. Someone says "he's a one-dimensional scorer who can't defend." The tool checks each part against the numbers and tells you which holds, which doesn't, and what the card can't answer.
Pressure-testing a hot take. A scorer has a big year and everyone assumes he's due to regress. The tool can show whether the goals rest on repeatable play-driving or on finishing that tends to cool, and it works the other way too: a player whose scoring is quietly understated.
Building a case for a player. If you're writing or arguing about how good someone actually is, it turns a wall of percentiles into a plain-language thesis you can stand behind, with every point traceable to a number.
Reading a young breakout honestly. The card is a three-year weighted average, so a 20-year-old's number rests on a short sample. The tool flags how far to trust it rather than treating the percentile as settled.
Understanding the metrics themselves. Ask what a stat measures and the one catch that keeps you from misreading it, without needing a verdict on a player.
It reads one analytics model's card and interprets it. It doesn't declare anyone good or bad in some absolute sense, and it only tells you what the numbers on the card support.
Related MCP server: NHL MCP Server
What you can ask it
A claim gets made about a player ("he's just a net-front guy, can't do more than that") and you want to know whether the data agrees.
You have an eye-test read and want to see if the metrics confirm it or complicate it.
A trade gets floated and you want an honest answer to "is X an upgrade on Y."
A young player breaks out and you want to know how far to trust it ("he's only 20 — is this real, or too early to bank on?"). The card is a three-year weighted average, so a young number rests on a short, recent sample: the upside and the uncertainty are both bigger than the single percentile lets on.
A scorer's goal total looks unsustainable ("is he due to regress?") and you want to know whether the scoring rests on repeatable play-driving or leans on hot finishing that tends to cool.
The flip side ("is he actually better than his goals say?"): a player who drives play but hasn't been finishing may have scoring that's understated — a positive-regression candidate rather than a fluke.
You hit a metric you don't know ("what does EV defense actually measure, and what's the catch?") and you want a plain-language definition plus the one caveat that keeps you from misreading it — for the metric itself, not a verdict on a player.
Why you can trust it
Every answer traces back to a number on the card. It tells you when a claim is half-right, and which half. It admits what the card cannot see instead of bluffing. It takes the noise out and leaves something you can explain to someone else and stand behind.
It interprets one model's read of a player. It does not declare anyone good or bad in some absolute sense.
The reading rules are also anchored in the model author's own published methodology write-ups — how the WAR model is built, how the expected-goals model was rebuilt, and how the impact numbers adjust for context. That's where the tool learned that replacement level sits near the 37th percentile (so a projection at or below it reads as replacement-level, not merely "below average"), that the power play is the model's noisiest read on both sides of the puck, that a forward's defensive impact is the less repeatable half of play-driving, and that zone starts, score state, and schedule are already adjusted for before the card is printed. These anchors sharpen the wording and the caveats; they never move a verdict.
How it works, under the hood
This is a local MCP server. The model you are
talking to (the LLM) reads the card image and handles the language. The server
does the deterministic part: it maps each percentile to a tier, grades claims
against the numbers, compares two players within the same position pool, attaches
the methodology caveats, and decides what the card cannot answer. The reading
rules live in config/interpretation.yaml and the metric definitions in
config/glossary.yaml, not in the model's memory, so the answers stay
consistent. Because the verdict is deterministic, the same card
values produce identical analysis on any host; what varies between hosts is how
well each model reads the card image and routes the numbers through the tools. It
works for forwards, defensemen, and goalies.
Five tools, thin wrappers over the engine:
assess_player(card, micro_card, edge_card, stat_card): overall tier, strengths and weaknesses, deployment, trajectory, caveats, a one-line summary. Takes a standard card, a microstat card, or a Game Score statcard (see below); given a player's standard card plus a micro card, an NHL Edge page, or a statcard, it adds articulation-only synthesis and vetting layers.adjudicate_claim(card, assertions): grades each claimsupported/partial/not_supported/unverifiable, with the cited number.compare_players(card_a, card_b, focus): component by component, an overall edge or an honest split, and a durability flag.explain_metric(metric): a plain-language definition of any card metric (skater, goalie, or microstat), plus its single most important interpretive caveat. It defines a metric in the abstract; it does not reason about a specific player.render_report(kind, result, title): turns the answer you just got into a downloadable, styled PDF report (see below).
Microstat ($10-tier) cards
The higher-tier subscription card — the dark card with a WAR row on top and three columns of AllThreeZones tracked data — is supported alongside the standard card, for forwards and defensemen (no goalie microstat card exists; goalies stay standard-only). It is a different data regime: one season of 5v5 per-60 percentiles rather than the standard card's three-year-weighted projection, no Proj. WAR headline, and no deployment context. The tools honor that regime rather than papering over it:
Style claims become checkable. "He's a rush player", "great skater", "physical", "relentless forechecker", "high motor", "net-front presence" — unverifiable on a standard card — are graded against the tracked numbers when a micro card is supplied, with the receipt cited. Playmaker claims grade on the passing process (dangerous passes thrown), not just assist outcomes. Style reads (hits, skating speed, forechecking) are never treated as value weaknesses; they describe how a player plays.
Built-in profile reads. The paired reads the tracking methodology scripts — shots vs chances (perimeter volume vs selectivity), chance assists vs shot assists (dangerous passer vs point-funneler), rush vs in-zone offense, the defenseman rush-defense trio ("tight gap but gets walked" vs "soft gap protecting the slot", or dominant across the line when all three run high), and a defenseman breakout-style family (four shapes for how he moves the puck out of his own end) — come back as named profiles with the numbers attached.
Both cards together. Supply a player's standard card and micro card in one question and the assessment adds an articulation-only synthesis: where this season ran hot or cold against the three-year projection, and where the tracked data backs (or undercuts) the WAR verdicts. The tier never moves.
Honest seams. A micro card has no Proj. WAR, so no overall tier is invented ("is he elite?" needs the standard card), and a micro card is never compared head-to-head against a standard card — single-season tracked percentiles and a blended projection are different pools. When a claim needs a box the supplied card doesn't carry, the answer names the card type that actually carries it — and says so plainly when none does.
NHL Edge vetting (optional)
Alongside either card you can also drop in a screenshot of the player's NHL Edge page — the league's own tracking, unrelated to HockeyStats. It is strictly supplemental: Edge data is never assessed on its own and never touches the claim or comparison tools; it rides along with an assessment and vets it, adding corroborations and contradictions between the card's verdicts and the tracking. The tier, strengths, and weaknesses never move because of it — same articulation-only contract as the both-cards synthesis.
The reading rules are deliberate about what Edge numbers can and can't say:
Rates drive the calls. Save percentages, starts over .900, and zone-time shares are judged off the raw value against the comparison average printed on the same page (with NHL's exact percentile cited when the site gives one, which it only does from the 51st up — below that it prints "<50th", and no number is ever invented for that bucket).
Counts never do. Shots against, goals against, saves, shots on goal — anything that accumulates with games played — is workload context only. A 22-game goalie can show a 99th-percentile goals-against count at the same save percentage a 44-game goalie posts with a below-average one; the rate is the truth, so counts stay descriptive with games played named.
Tools are style. Hardest shot, max skating speed, and miles skated are physical-tools color, never evidence of offensive value — players with near-identical tool readings sit at opposite ends of production.
Zone time is deployment-shaped. Territorial tilt can back (or honestly contradict) an EV impact verdict, but it always carries the deployment caveat: where the puck lives with a player on the ice is not an isolated impact.
Game Score statcards (HOCKEYSTATCARDS)
A fourth card family: the HOCKEYSTATCARDS player card (models by Dom Luszczyszyn, data NaturalStatTrick), built on Game Score — a single-game productivity stat on a points-like scale — and its GSVA evolution. The card shows three rating dials (Offense / Defense / Net, in goals above or below positional average, each with a printed percentile), a per-game Game Score average, and adjusted 5v5 on-ice season totals. It is a third data regime: one season of results, not a projection, from a different analyst's model than the projection card. The tools honor all of that:
Assessed on its own. A statcard alone gets a full assessment: the tier comes from the net-rating percentile, never the rating's sign (the distribution is right-skewed, so a slightly negative rating can sit near the middle of the pool — the card is honest about that trap), with a finishing-luck read (goals vs individual expected goals), on-ice conversion reads, and special-teams deployment where a 0.00 box means no role, never a weakness.
Cross-model synthesis. Supply a player's projection card and statcard together and the assessment adds an articulation-only synthesis: where this season's results agree with the projection (the strongest corroboration two independent models can give) and where they diverge — a finding to surface, never an error to resolve. The tier never moves.
Claims and comparisons. Season claims ("he ran hot", "he drives play", "no power-play role") grade against the statcard's printed numbers; statcard-vs-statcard comparisons work within a position pool, keyed on the net percentile, with an honest split when the dials disagree and a durability flag when the edge rides a hot conversion year. Statcard-vs-projection-card comparisons are refused as cross-regime.
Goalies, reduced. Goalie statcards carry only the trustworthy boxes (net rating, Game Score average, TOI, and a direction-only goals-vs- expected read) — the sampled cards showed the other goalie boxes are buggy or unpopulated, and the engine says so rather than guessing.
PDF reports
After any assess, compare, or claim-check answer, ask for a PDF (the assistant
will offer one) and you get a styled report of that exact verdict written to
~/Documents/HockeyCardReports/ — named after the player(s), the report kind,
and the date. Eight report kinds: skater assessment, goalie assessment,
microstat assessment, statcard assessment (skater and goalie variants),
head-to-head comparison, graded claim check, and an
"interpretive" kind for
reads the engine has no tool for (line synergy, goalie support, free-form
questions), which is prominently badged "Interpretive read · AI — not an
engine verdict" so an AI read can never pass as an engine one.
Two honesty rules are enforced, not advisory: the report is rendered from the
same structured result the engine just returned (a retyped or reconstructed
result is rejected), and the source card image is never embedded. Rendering is
fully local — an HTML template with bundled fonts, converted by
WeasyPrint with no headless browser and no network.
On macOS, WeasyPrint needs one system library: brew install pango.
What you need
A hockeystats.com subscription and a player card you have pulled yourself. The tool does not fetch, scrape, or store cards. It only interprets a card you supply, and the LLM reads the card image at runtime, so the server itself only ever sees the numbers.
To run the server you need Python 3.11+ (tested on 3.14).
How to run it
This is a standard MCP server that speaks over stdio, so any MCP-capable client can use it. It was built and tested with Claude Desktop on macOS. The same command works for other clients; you just put it in that client's MCP config.
Install (one time):
git clone https://github.com/augforce/hockey-card-analyst.git cd hockey-card-analyst python3 -m venv .venv .venv/bin/python -m pip install fastmcp pydantic PyYAMLRegister the server with your client. Every MCP client needs the same two things: the command (the venv Python) and one argument (the server script). Use absolute paths for your machine:
command:
/absolute/path/to/hockey-card-analyst/.venv/bin/pythonargs:
["/absolute/path/to/hockey-card-analyst/src/server.py"]
Claude Desktop (tested). Edit
~/Library/Application Support/Claude/claude_desktop_config.json(on Windows,%APPDATA%\Claude\claude_desktop_config.json) and merge:{ "mcpServers": { "hockey-card-analyst": { "command": "/absolute/path/to/hockey-card-analyst/.venv/bin/python", "args": ["/absolute/path/to/hockey-card-analyst/src/server.py"] } } }Quit Claude Desktop fully and reopen so it reloads the config.
Gemini CLI. Add the same block under
mcpServersin your Gemini settings (~/.gemini/settings.json), then restart the CLI.Other stdio clients (Cursor, VS Code, Cline, Continue, the OpenAI Agents SDK, and similar). Each has its own place to register an MCP server, but the entry is the same command and args shown above.
ChatGPT (more involved). This is a different, heavier deployment than the stdio hosts above. ChatGPT connects to a remote MCP endpoint rather than a local stdio process, so you would run this server as a public HTTP endpoint using FastMCP's HTTP transport. Two things to know going in: FastMCP's HTTP transport enables DNS-rebinding/origin protection by default, which returns 403 to every client until you configure the allowed origins and hosts; and exposing a public endpoint is a security responsibility you own. See the FastMCP HTTP transport docs (https://gofastmcp.com) for transport and security configuration. This path is not tested here.
Confirm the loop. Start a conversation, give the model a player card image, and ask in plain language, for example:
Someone told me this kid is an elite two-way center already. True?
The model should read the card, route it through the tools, and answer from the numbers: back the offense where the card supports it, push back on the two-way side if the defensive numbers do not, note how the player is deployed, and flag the trajectory.
Scope and sourcing
The tools read the card and nothing else. Every verdict traces back to a percentile on the card, so the whole answer is auditable — you can check each claim against a number you can see.
Team, roster, and contract context — trades, who's on the roster, who leads a
team in scoring, recent game results — is out of scope by design. The tools
don't fetch it and don't guess it (adjudicate_claim returns such claims as
unverifiable). Keeping that context out is what keeps the auditable trail
clean. This is the default, no-setup behavior: card-bound and honest.
Optional: let the host model add outside context
If you want the host model to pull outside context (trades, contracts, roster fit) and weave it into the answer, you can opt in with a standing instruction. Put it wherever your host keeps persistent instructions: a system prompt, the host's custom instructions, or a project. In Claude Desktop, for example, that is a Project instruction (Projects, then your project, then instructions); other hosts have their own equivalent. It lives in the host app, not in the MCP config JSON, and not in this repo. Paste this in:
When assessing hockey cards, anything the card itself can't answer (trades,
contracts, current team, roster context, recent stats) may be pulled from the
web. When you do, clearly mark which parts of the answer came from the web
rather than the card, and add a brief note that web-sourced facts should be
verified before being taken at face value. Card-derived verdicts come from the
hockey-card-analyst tools and are traceable to the numbers; web facts are
supporting context, not tool output. Keep the two visibly separate.With this in place the model labels web-sourced facts separately from card-derived verdicts, so the audit trail stays intact: the card verdicts remain traceable to the numbers, and the outside context is clearly flagged as unverified. Web augmentation is an opt-in you configure and label yourself.
Intellectual property
This repo ships logic and rules, not HockeyStats data. You bring your own card, accessed through your own subscription; the server only interprets a card you already have. Do not scrape, cache, or redistribute HockeyStats cards or their underlying data.
Development
Run the tests:
.venv/bin/python -m pytestThe engine has no network or vision dependencies. It only transforms structured
numbers, so the suite is fast and deterministic. See DECISIONS.md for the
design rationale behind the reading rules.
Status
v1.1: the three analysis tools plus explain_metric and PDF reports, for
forwards, defensemen, and goalies — now reading the standard card, the
$10-tier microstat card (style claims, profile reads, and both-cards
synthesis), NHL Edge pages (supplemental vetting), and HOCKEYSTATCARDS Game
Score statcards (standalone season assessment plus cross-model synthesis),
with the reading rules anchored in the models' published methodology
write-ups. Served over MCP and tested end to end on Claude Desktop. See
DECISIONS.md for the full build log.
Available Tools
5 toolsadjudicate_claimA
Grade a claim about a player against the card. ALWAYS route claims through this tool — never eyeball a claim yourself.
YOU decompose the natural-language claim into a list of assertions; the server
grades each one. Each assertion is {dimension, direction[, text]} where
direction is "high" or "low" and dimension is a card dimension id or a
recognizable phrase. Dimension ids include — skater: finishing, playmaking,
two_way, power_play, penalty_kill, discipline, overall_skater, competition,
teammates; goalie: game_stealer, soft_goals, reliability, no_stinkers,
goalie_consistency, goalie_rebounds, goalie_pk, workhorse, overall_goalie.
Include the original phrase as text so it can be echoed back.
Dimension ids are NOT the card's schema field names. NEVER pass ev_offense
or ev_defense (or any other card field) as a dimension; map the claim to a
dimension id instead — an offense / scoring claim -> finishing or
overall_skater; a defensive / two-way claim -> two_way.
Each verdict comes back as supported / not_supported / partial / unverifiable, with the cited metric value and a one-line reason, plus an overall read. Cite the returned value in your answer — never substitute your own number.
unverifiable is first-class and MUST be surfaced, not hidden: claims the card
cannot see (playing style, net-front / "sits in front of the net", "leading
scorer next season" and other team-context claims) come back unverifiable on
purpose. A direction that contradicts the metric comes back not_supported with
the number as the receipt.
Scope: this tool grades ONLY what's on the card. Beyond the card-can't-see
claims above, that also rules out trades, contracts, current team, and recent
game stats — out of scope, and unverifiable for the same reason. If you fill
any such gap from outside the card (e.g. the web), mark it clearly as NOT from
the card and flag it for verification; keep card-derived verdicts separate from
outside context.
card: the same JSON card object as assess_player. assertions: a list of
{dimension, direction, [text]}.
After presenting the graded claim, ALWAYS close your answer by offering the
user a downloadable PDF report of it — generated with the render_report tool
(kind "claim_check", the original claim as title), passing THIS result
verbatim.
| Name | Required | Description | Default |
|---|---|---|---|
| card | Yes | ||
| assertions | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description fully discloses behavioral traits: decomposition into assertions, grading outcomes (supported/not_supported/partial/unverifiable), requirement to surface unverifiable, and scope limitations. Adds significant value beyond structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is verbose, containing procedural steps (like offering a PDF report) that could be shortened. However, it is well-structured and front-loaded with purpose and key warnings.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (2 params, nested objects, no enums, output schema present), the description covers input format, behavior, return values, and post-processing guidance. It is fully complete for an agent to use correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Despite 0% schema coverage, the description richly explains both parameters: 'card' is a JSON object and 'assertions' is an array with required keys (dimension, direction, text) and lists valid dimension ids. Adds much more meaning than the bare schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool grades a claim about a player against the card, explaining the decomposition into assertions. It distinguishes from sibling tools like assess_player and compare_players by focusing on claim adjudication.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly instructs agents to always route claims through this tool rather than eyeballing, and clarifies scope (only card data, no trades/contracts). Lacks explicit comparison to sibling tools but provides strong context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
assess_playerA
Assess one player's card: overall tier, strengths, weaknesses, deployment, trajectory, caveats, and a one-line summary.
YOU (Claude) read the card image and extract the fields; this server never sees the image — pass it clean structured data. The server maps percentiles to tiers, picks the strengths/weaknesses, and attaches the caveats. Narrate from what it returns, not from how you think WAR models generally work — the result carries the correct framing inline.
card is one JSON object. Skater (forward or defenseman):
name, position (C/LW/RW/L/R/F; D for a defenseman), [team, age],
[toi_role, cap, competition, teammates], ev_offense, ev_defense,
pp (null if NA), pk (null if NA), finishing, penalties, proj_war_pct,
[goals, first_assists], [war_pct_trend: list of {season, value}].
Goalie (no position; has role):
name, [team, age], [gp_pct], role (Starter/1A/1B/Backup), [cap], proj_war_pct,
even_strength, penalty_kill, high_danger, med_danger, low_danger,
quality_starts, excellent_starts, bad_starts, rebound_control, consistency,
[war_per60_trend, sv_vs_xsv_trend].
All percentiles are integers 0-100, already oriented so higher is better — including goalie Bad Starts and Consistency; do NOT invert them. A role the player doesn't have (e.g. no PK) is null/NA, not 0 — NA is an absence of role, not a weakness. Some cards (e.g. a UFA's) print a blank Age and show no team: omit team/age rather than guessing, and never infer the team from the jersey or photo.
Guardrails: never invent a stat that isn't on the card; a defenseman's finishing is descriptive only (excluded from his WAR); surface the returned caveats rather than dropping them.
Narrate the returned STRUCTURE, not your own regrouping: "strengths" and
"weaknesses" are exactly the returned lists. The descriptive reads (goals,
first assists) are supporting color the engine deliberately keeps OUT of the
value verdict — you may cite them as descriptive color, but NEVER present
them as strengths, weaknesses, or part of the WAR case.
Scope: this tool interprets ONLY what's on the card. Anything the card can't see — trades, contracts, current team, roster context, who leads a team in scoring, recent game stats — is out of scope and it does not provide it. If you fill such a gap from outside the card (e.g. the web), mark that content clearly as NOT from the card and note it should be independently verified; keep card-derived verdicts (traceable to the numbers) visibly separate from outside context (unverified).
After presenting this assessment, ALWAYS close your answer by offering the user a downloadable PDF report of it — generated with the render_report tool (kind "assess_skater" or "assess_goalie"), passing THIS result verbatim.
| Name | Required | Description | Default |
|---|---|---|---|
| card | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden and excels. It explains the tool's internal behavior: mapping percentiles to tiers, picking strengths/weaknesses, attaching caveats. It also warns against inverting goalie stats, handling NAs, and not inventing stats. This fully informs the agent of the tool's behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is extremely verbose, containing lengthy meta-instructions for the AI agent about how to present output, guardrails, and narratives. While structured, it goes far beyond concise documentation, making it harder to parse quickly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the complexity of the tool (single parameter with elaborate nested object, output schema exists), the description is exceptionally complete. It covers input structure, processing logic, and output formatting, leaving no significant gaps for an agent to infer.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0% with only 'card' as an untyped object. The description compensates by exhaustively documenting the expected structure for skaters and goalies, including all fields and their meanings. This is a complete and detailed definition of the parameter's semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states the tool's purpose clearly: 'Assess one player's card: overall tier, strengths, weaknesses, deployment, trajectory, caveats, and a one-line summary.' It distinguishes itself from siblings like compare_players by focusing on a single player's assessment, though not explicitly contrasting them.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides extensive guidance on when and how to use the tool, including instructions for the AI to extract fields from the card image and pass structured data. It sets guardrails and clarifies what not to do, but does not explicitly state when to avoid this tool in favor of siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
compare_playersA
Compare two players: per-component gaps, an overall edge (or an honest split), a durability flag, and caveats.
Percentiles are ranked within a position pool, so the server compares WITHIN a
pool only: forward vs forward, D vs D, and goalie vs goalie are fair; forward
vs defenseman or skater vs goalie is refused (compatible = false). Never
present a cross-pool winner — surface the refusal.
When the components genuinely split — one player better on offense while the
other is better on defense; for goalies, one a game-stealer while the other is
the reliable floor — the server returns NO single winner (overall_edge null,
edge_kind "split", "better at what"). Do not collapse that into a winner;
report the tradeoff. An edge built mainly on finishing (skaters) or resting on a
low-consistency goalie is flagged less durable — pass that along.
Scope: this tool compares ONLY what's on the cards — it knows nothing about trades, contracts, teams, roster fit, or recent stats. If you add such context from outside the cards (e.g. the web), mark it clearly as NOT from the cards and flag it for independent verification; keep the card-derived comparison separate from outside context.
card_a, card_b: card JSON objects as in assess_player. focus (optional):
"offense" / "defense" / "overall" / a role (e.g. "power play") to narrow it.
After presenting the comparison, ALWAYS close your answer by offering the user a downloadable PDF report of it — generated with the render_report tool (kind "compare"), passing THIS result verbatim.
| Name | Required | Description | Default |
|---|---|---|---|
| focus | No | ||
| card_a | Yes | ||
| card_b | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full burden. It discloses that the tool is read-only (only compares card data, no modifications), reports refusal for cross-pool comparisons, handles split decisions, and flags durability concerns. Minor lack of explicit 'idempotent' or 'non-destructive' statement.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is thorough but verbose, with some repetition (e.g., cross-pool refusal mentioned twice). It could be tightened while retaining key details. Front-loading the output components is good, but the instructional tone takes extra space.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given complexity, the description covers all essential aspects: purpose, constraints (position pools, split logic, durability), input parameters, output structure (gaps, edge, durability, caveats, compatibility), and integration with sibling tool 'render_report'. No gaps noted.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, but the description adds meaning: explains 'card_a' and 'card_b' as card JSON objects (referencing 'assess_player'), and 'focus' as optional with examples ('offense', 'defense', 'overall', role). This aids the agent in understanding parameter values beyond the bare schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool compares two players, producing per-component gaps, an overall edge or split, a durability flag, and caveats. It distinguishes itself from siblings like 'assess_player' (single player) and 'adjudicate_claim' by focusing on pairwise comparison.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains when the tool is appropriate: for comparing player cards within the same position pool, and refuses cross-pool comparisons. It cautions that the tool only uses card data, not external context like trades or stats, guiding when to supplement with other sources. However, it does not explicitly contrast with sibling tools like 'assess_player'.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
explain_metricA
Define a single card metric: what it measures, plus its one most important interpretive caveat.
A thin dictionary lookup over the card's percentile boxes (skater and goalie).
Pass the schema field name (e.g. ev_defense, bad_starts) or a natural
phrase (e.g. "even strength defense", "no stinkers"); it resolves both. An
input that isn't a card metric comes back with found false and a clear
message — it never guesses.
Returns: {query, found, metric, label, definition, caveat, message}. The
caveat is the same one the other tools attach, served from one source.
Scope: this tool DEFINES metrics in the abstract — it does NOT reason about any specific player. A deeper "why is this a risk for HIM" question is yours to answer from these definitions plus that player's assess_player result; it is not something this tool computes. Use it to ground your narration of a metric's meaning, not as a verdict.
| Name | Required | Description | Default |
|---|---|---|---|
| metric | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full burden. It discloses behavior: thin dictionary lookup over percentile boxes, never guesses (returns found false with message), returns specific structure, and that caveat is from a unified source. It also states the tool does not reason about players.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and front-loaded with the main purpose. Each sentence adds value, though a bit verbose in parts. Still efficient for the information provided.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity (one param, no annotations, but has output schema), the description is complete. It explains input, behavior, output structure (listing fields), and limitations. With output schema existing, it doesn't need to detail return values but does so briefly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0% for the single parameter 'metric'. The description adds significant meaning: metric can be a schema field name or natural phrase, provides examples, and explains behavior when input is not a card metric. Fully compensates for lack of schema description.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool defines a single card metric, its measure, and its top caveat. It specifies the resource (card metric) and action (define/explain), and distinguishes from siblings like assess_player by noting it does not reason about specific players.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly provides when to use (to ground narration of a metric's meaning) and when not to (as a verdict). It notes that for player-specific questions, one should use assess_player results, suggesting an alternative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
render_reportA
Render an answer into a downloadable, styled PDF report; returns the absolute file path.
After completing ANY assess / compare / claim answer, ALWAYS end by asking the user if they'd like a downloadable PDF report of it — every time, as the closing line of your answer, not only when they hint at it. Generate the PDF when they say yes (or asked for a report/PDF/download up front), then give them the returned path.
result must be the EXACT structured object the engine tool just returned
(assess_player / compare_players / adjudicate_claim), passed through
verbatim — the same dict, not a summary of it. NEVER retype, round, rebuild,
or trim fields: the server validates against the engine's own result shape
and rejects anything else. If you no longer have the engine result, call the
engine tool again first. Never pass the card, and never embed the card image.
kind selects the template:
"assess_skater": an assess_player result for a forward or defenseman
"assess_goalie": an assess_player result for a goalie (has danger_profile)
"compare": a compare_players result (works for splits and refusals too)
"claim_check": an adjudicate_claim result — pass the original claim sentence as
title(it headlines the report and names the file)"interpretive": YOUR OWN prose, for questions with no engine tool (line synergy, goalie support, free-form reads). Pass {title, tone ("positive"/"negative"/"mixed"/"neutral"), players: [names], sections: [{heading, body}, ...], caveat, summary}. The report is prominently badged "Interpretive read · AI — not an engine verdict". Never pass engine output as interpretive, and never pass your own prose under an engine kind — the badge is how the reader tells them apart.
title (optional) overrides the report heading; player names still come
from the result. The PDF lands in ~/Documents/HockeyCardReports/
(created if missing; filename = player(s) + kind + date).
| Name | Required | Description | Default |
|---|---|---|---|
| kind | Yes | ||
| title | No | ||
| result | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided, so description bears full responsibility. Discloses behavior thoroughly: returns absolute file path, creates directory if missing, filename format, server-side validation of result shape, interpretive badge, and prohibition on embedding card image. This level of detail is exceptional for behavioral transparency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is comprehensive and logically structured, with front-loaded purpose and clear sections for usage, parameters, and examples. However, it is somewhat verbose; some sentences could be trimmed without losing meaning. Overall, every sentence earns its place given the complexity, but there is minor room for tightening.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (multiple template kinds, strict result requirements, interactive usage), the description is highly complete. It covers all scenarios: directory creation, file naming, server-side validation, behavior for each kind, and even the interpretive badge. The presence of an output schema (noted in context signals) means return values need no further explanation, so no gap exists.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, but the description adds extensive meaning beyond raw schema. It explains that 'kind' selects a template with specific valid values and behaviors, 'result' must be the exact engine output (not a summary), and 'title' is optional. For interpretive kind, it details the required nested structure. This adds significant semantic value.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool renders an answer into a downloadable, styled PDF report and returns the file path. It specifies the verb 'render', the resource 'answer into PDF', and the output. The description also distinguishes from sibling tools by focusing on reporting/templating, not on the analysis itself.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit instructions on when to use: after assess/compare/claim answers, always ask user if they want PDF, generate on affirmative. Details what to pass as result (exact engine object) and what not to do (never modify). Specifies template kinds and when to use interpretive. Offers clear exclusions and alternatives, fulfilling the highest standard.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
TDQS
Each tool has a clearly distinct purpose: adjudicate_claim grades claims, assess_player evaluates a single player, compare_players compares two players, explain_metric defines a metric, and render_report generates PDFs. There is no overlap or ambiguity.
All tool names follow a consistent verb_noun pattern with underscores (adjudicate_claim, assess_player, compare_players, explain_metric, render_report), making them predictable and easy to understand.
With 5 tools, the server is well-scoped for its purpose of analyzing hockey cards. Each tool covers a core operation without unnecessary bloat or missing functionality.
The tool set covers the full lifecycle for hockey card analysis: single player assessment, comparison, claim verification, metric explanation, and report generation. There are no obvious gaps for the stated domain.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Quant sports analytics: 19 read-only tools across 12 leagues, projections, methods, track record.
The hockey data API. Stats, odds, and everything between. REST API and MCP server.
Live sports stats and pre-computed analysis for AI assistants across NBA, MLB, NFL, and NHL.
Read-only fantasy analysis for ESPN, Yahoo, and Sleeper leagues via MCP
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceProvides access to live NHL game data, team and player statistics, standings, schedules, playoff information, and head-to-head comparisons through natural language queries using official NHL APIs.MIT
- FlicenseAqualityDmaintenanceProvides access to live NHL game data, player and team statistics, standings, schedules, playoff brackets, and historical comparisons through natural language queries using the official NHL API.11
- FlicenseNot gradedqualityDmaintenanceProvides access to live NHL data including player statistics, team standings, game scores, schedules, and playoff information through 40+ NHL API endpoints.3
- AlicenseAqualityDmaintenanceReal-time sports card pricing, market analysis, arbitrage detection, grading ROI, investment advice, and player stats (NBA/NFL/MLB). 9 tools for AI agents helping collectors and investors.92MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/augforce/hockey-card-analyst'
If you have feedback or need assistance with the MCP directory API, please join our Discord server