PeakCam Snow
Server Details
Live snow reports, SNOTEL measurements, webcams and powder rankings for 150 ski resorts.
- Status
- Healthy
- Uptime
- 100.0% over 20 days
- Last Tested
- Transport
- Streamable HTTP · MCP 2025-11-25
- URL
- Repository
- jaredschueler07/peakcam
- GitHub Stars
- 0
- ChatGPT
- –
- Claude
- –
TDQS
Scored across 21 tools
Most tools have clearly distinct purposes, and the descriptions explicitly disambiguate close pairs like get_resort_conditions vs get_stations vs get_snow_history. However, the `ask` router overlaps with every query tool, and there is some conceptual overlap among conditions, stations, and score/ranking tools, which could cause hesitation.
Names are almost entirely snake_case verb_noun patterns (get_*, compare_*, find_*, list_*, search_*), making the set highly predictable. The only minor deviation is `ask`, which is a bare verb rather than a verb_noun pair.
21 tools is on the heavy side, but the domain is broad (resorts, snow conditions, forecasts, models, cams, alerts, rankings, history). Each tool covers a distinct query type, so the count is slightly over but reasonable for the scope.
The surface is extensive for a read-only snow-data domain, covering discovery, conditions, forecasts, history, rankings, cams, and alerts. Minor gaps include no direct 'list all resorts' tool and no standalone non-snow weather forecast, but agents can work around these with search_resorts, get_forecast, and get_stations.
Available Tools
21 toolsaskAsk PeakCamARead-onlyIdempotentInspect
One natural-language question in, one tool result out, deterministically: the router resolves the resort by name or nickname, picks an intent from the wording (snow, open/closed, forecast, cams, history, compare, where did it snow, percent of normal, profile, regions, alerts) and calls the matching tool. Returns the tool's data, the resort, citation URLs and a dated sentence to quote. Answers answerable: false with suggestions rather than guessing. No language model is involved.
| Name | Required | Description | Default |
|---|---|---|---|
| question | Yes | The question as the user asked it, up to 300 characters, e.g. "is Alta open" or "where did it snow most in Colorado". |
Output Schema
| Name | Required | Description |
|---|---|---|
| asOf | Yes | ISO instant of the newest report the sentence used; null when it used none. |
| data | Yes | The tool's structured result (its documented `outputSchema`), or null. |
| tool | Yes | The PeakCam MCP tool whose result is in `data`. |
| place | Yes | |
| intent | Yes | |
| resort | Yes | The resort the question named (the first, for a comparison). |
| license | Yes | |
| resorts | Yes | Every resort the question named, in order. |
| question | Yes | |
| sentence | Yes | A dated, source-labelled sentence that can be quoted verbatim. |
| arguments | Yes | The arguments that tool was called with, so the call can be repeated over MCP. |
| citations | Yes | PeakCam URLs to cite, the resort page first. |
| answerable | Yes | False when the router found no resort or no intent it could serve; `data` is then null and `suggestions` says what to ask. |
| attribution | Yes | |
| generatedAt | Yes | |
| suggestions | Yes | Questions the router can answer, offered when it could not answer this one. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (readOnly, idempotent, non-destructive, closed-world), and the description adds genuinely new behavioral facts: the routing is deterministic, no LLM is involved, the response includes the tool's data plus resort, citation URLs and a dated quotable sentence, and unanswerable questions return `answerable: false` with suggestions rather than a guess. The failure mode disclosure is exactly the kind of context an agent cannot get from 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?
Front-loaded with the core contract in the first clause, then progressively adds routing detail, return shape, and failure behavior. Dense but every sentence carries information; the long parenthetical intent list is the only slightly heavy element.
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?
Although an output schema exists (so return values need not be described), the description still sketches the response shape and the `answerable: false` path, and it covers the deterministic, no-LLM guarantee. Nothing an agent needs to decide whether and how to call this router is missing.
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 100% and the single `question` parameter is well documented with examples and a 300-char limit, so baseline is 3. The description goes further by explaining how the question string is interpreted — resort resolved by name or nickname, intent inferred from wording — which is meaningful semantics the schema cannot express.
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?
States a specific verb+resource with unusual precision: 'One natural-language question in, one tool result out,' and immediately explains the routing mechanism (resolve resort, pick intent, call matching tool). This clearly distinguishes it from the sibling tools, which each handle a single fixed intent.
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 enumerated intent list (snow, open/closed, forecast, cams, history, compare, where did it snow, percent of normal, profile, regions, alerts) tells an agent exactly which classes of question belong here and maps them to the sibling tools it will dispatch to. It stops short of explicitly stating when to call this router instead of invoking a specific sibling directly, which is the one remaining routing decision.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
compare_modelsCompare forecast modelsARead-onlyIdempotentInspect
How each weather model has verified at a resort over the trailing 90 days, graded against measured snow (SNOTEL depth change, clipped at zero), and what each model says for the next 7 days right now. Per model: rank, mean absolute error at day 1/3/7 (cm), bias ratio (total forecast over total measured; above 1 over-forecasts), samples, plus the current 7-day total and horizon. truthBasis and measuredDays say what the grading rested on; a resort with no measured series has no scores. The PeakCam blend is graded by the same rule and appears as blend.
| Name | Required | Description | Default |
|---|---|---|---|
| slug | Yes | PeakCam resort slug, lowercase kebab-case, e.g. `breckenridge` or `ski-portillo`. Get it from search_resorts. |
Output Schema
| Name | Required | Description |
|---|---|---|
| name | Yes | |
| note | Yes | |
| slug | Yes | |
| scores | Yes | Ranked; empty until the scorer has measured days. |
| credits | Yes | |
| outlook | Yes | The newest stored run per model: what each says for the next 7 days. |
| station | Yes | |
| bestModel | Yes | |
| periodDays | Yes | |
| truthBasis | Yes | |
| accuracyUrl | Yes | |
| generatedAt | Yes | ISO-8601 UTC instant the result was generated. |
| scoredPoint | Yes | |
| canonicalUrl | Yes | |
| measuredDays | Yes | |
| blendTotal7dIn | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the read-only/idempotent/closed-world profile, so the burden is lighter, yet the description adds real behavioral context: how grading is done (SNOTEL depth change clipped at zero), what bias ratio means, and the edge case that a resort with no measured series has no scores. It doesn't cover rate limits or latency, keeping it at a 4.
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 core purpose is front-loaded in the first clause, and the field-level detail that follows is largely load-bearing. It is dense and slightly list-like, but no sentence is obviously filler.
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?
With an output schema present the description need not unpack return values, yet it explains the per-model fields, truthBasis and measuredDays, and the blend entry, making it broadly complete for a single-parameter analytical tool. The main gap is the absence of explicit guidance on when to reach for this versus sibling forecast tools.
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?
There is a single parameter with 100% schema description coverage, so the schema already documents the slug format and its source. The description adds nothing about the slug beyond what structured fields provide, which is the baseline 3.
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 names a specific resource and scope: per-model verification at a resort over 90 days plus the current 7-day forecast. An agent can immediately tell this is a model-accuracy comparison and distinguish it from resort-level siblings like compare_resorts or get_forecast.
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?
Usage is only implied — you call it to see which forecast model has verified best at a given resort. There is no explicit statement of when to prefer this over get_forecast or compare_resorts, and no exclusions. The only routing hint is the slug field pointing to search_resorts.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
compare_resortsCompare resortsARead-onlyIdempotentInspect
Side-by-side latest snow, today's Snow Score (0–100 with a rating; get_score explains it), season status and cam counts for 2–6 resorts. Every slug must resolve; an unknown one returns suggestions.
| Name | Required | Description | Default |
|---|---|---|---|
| slugs | Yes | 2–6 resort slugs. |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | Yes | |
| resorts | Yes | |
| generatedAt | Yes | ISO-8601 UTC instant the result was generated. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover readOnly, idempotent and non-destructive semantics, and an output schema exists. The description adds genuinely new behavior: unknown slugs cause failure but return suggestions, which tells the agent how to recover from bad input.
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?
Two sentences, no filler; the field list and the input/resolution rule are both front-loaded and each clause carries distinct information.
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?
With annotations covering safety, a full output schema covering return values, and a 100%-covered input schema, the description only needs to add field scope and input-resolution behavior — both present. Nothing required to call it correctly is missing.
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 100%, so the baseline is 3, but the description adds validation semantics beyond the schema — 'every slug must resolve' and the suggestion-returning fallback on unknown slugs — which shapes how the agent should supply and vet the slugs.
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?
States a specific verb (compare), resource (resorts), a precise scope (2–6), and enumerates the compared fields: latest snow, Snow Score, season status, cam counts. The cardinality and cross-resort nature cleanly separate it from single-resort siblings like get_resort_conditions.
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?
Usage is implied by the '2–6 resorts / side-by-side' framing, and it points to get_score for Score explanation plus search_resorts (via schema) for slug sourcing. It never explicitly says when to prefer this over get_resort_conditions or get_resort_profile for a single resort.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
find_powderFind powderARead-onlyIdempotentInspect
Rank resorts by new snow in the last 24 or 48 hours, optionally within one state/province and above a minimum. Pass sourceOnly="snotel" to answer "where did it snow most, measured only" with station data alone. Resorts with no report are left out; zero inches is a measurement. Each row also carries today's Snow Score (score, 0–100 with a rating) when one is stored; get_score explains it. Sources: snotel = measured at a USDA NRCS SNOTEL station near the resort (station elevation, not the summit), open_meteo = weather-model estimate for resorts without a station.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Rows to return, 1–25. | |
| state | No | US state or Canadian province code (`CO`, `UT`, `BC`), or for the Andes the country name PeakCam lists (`Chile`, `Argentina`). Case-insensitive. | |
| window | No | Which window ranks first; the other breaks ties. | 24h |
| minInches | No | Keep only resorts with at least this many inches in the window. | |
| sourceOnly | No | `snotel` keeps only station-measured reports and drops model estimates. |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | Yes | |
| window | Yes | |
| filters | Yes | |
| license | Yes | |
| results | Yes | |
| attribution | Yes | |
| generatedAt | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the read-only/idempotent safety profile, so the description focuses on semantics an agent cannot get from structured fields: resorts with no report are excluded, zero inches counts as a real measurement, each row carries a stored Snow Score, and the two sources differ (station-measured at station elevation vs model estimate for resorts lacking a station). That is exactly the kind of behavioral context that prevents misreading results.
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?
Front-loads the core purpose in the first clause, then layers filtering semantics, then source definitions. Every sentence carries information, though the trailing source-definition sentence is dense and could be slightly tighter.
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?
With an output schema present, return-shape detail is unnecessary, and the description still supplies the interpretation layer (score meaning, source provenance, exclusion of unreported resorts) that the schema and annotations cannot. Nothing an agent needs to call or read this tool correctly is missing.
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 100%, so baseline is 3, but the description adds meaning beyond the schema: why sourceOnly exists (isolate station-measured answers) and how zero inches and missing reports should be interpreted. Window tie-breaking and state format are already in the schema, so this sits just above baseline rather than far above it.
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?
States a specific verb and resource with scope: rank resorts by new snow over a 24h/48h window, with optional state and minimum-inch filters. The 'powder' framing plus explicit window and filtering behavior distinguishes it from generic siblings like get_snow_history or get_leaderboard without needing to open a schema.
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?
Gives concrete usage conditions: pass sourceOnly="snotel" to answer 'where did it snow most, measured only', and points to get_score for interpreting the score field. It does not explicitly route between this tool and similar siblings (get_snow_history, compare_resorts), but the context provided is clear and actionable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_alert_optionsAlert optionsARead-onlyIdempotentInspect
How to be told when it snows, without this server writing anything: the powder-alert threshold and schedule, the e-mail, webhook (Standard Webhooks, signed), Atom and iCal channels, the per-resort public Atom feed, the webhook payload contract, and the manage page where a person registers a destination. Pass a slug to get that resort's feed URL.
| Name | Required | Description | Default |
|---|---|---|---|
| slug | No | Optional: a resort slug, to fill in its public Atom feed URL. |
Output Schema
| Name | Required | Description |
|---|---|---|
| writes | Yes | This tool never subscribes anyone; it only explains how. |
| webhook | Yes | |
| channels | Yes | |
| schedule | Yes | |
| manageUrl | Yes | Where a person subscribes and registers webhooks; e-mail verified, no password. |
| resortFeed | Yes | |
| generatedAt | Yes | ISO-8601 UTC instant the result was generated. |
| thresholdInches | Yes | New snow in 24 h (measured) or storm total (forecast) that fires an alert. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, and the description reinforces this with 'without this server writing anything.' It goes beyond the annotations by disclosing the webhook signing scheme (Standard Webhooks, signed), the payload contract, supported channel types, the per-resort public Atom feed, and the human-facing manage page. That is substantive behavioral context a caller could not infer from the safety hints alone.
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 single long sentence is a comma-heavy enumeration of channels, contracts, and pages that mixes purpose with a parts list. It is front-loaded toward what the tool covers, but the run-on structure makes it harder to parse than it needs to be. Some listed items (iCal, Atom, manage page) could be trimmed or reorganized.
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 a single optional parameter, rich annotations, and an output schema (so return values need not be described), the description covers enough for correct invocation: what is returned, what the slug does, and that nothing is written. Only explicit sibling routing and any error/none-found behavior are missing.
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 100%, so the schema already documents the single optional slug parameter, including that it fills in the public Atom feed URL. The description restates this same effect ('Pass a slug to get that resort's feed URL') without adding format, constraints, or fallback behavior. Baseline 3 is appropriate when the schema carries the parameter burden.
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 frames the resource: the alert threshold/schedule, delivery channels (e-mail, webhook, Atom, iCal), webhook payload contract, and the manage page. The verb is implied rather than stated ('How to be told when it snows'), but an agent can tell this returns alert-configuration information. It is distinguishable from siblings like get_forecast or find_powder, though it never names 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?
Usage is only implied: 'Pass a slug to get that resort's feed URL' tells the agent what the optional parameter accomplishes, and 'without this server writing anything' hints at a non-mutating context. There is no explicit when-to-use-this-vs-alternatives guidance, so the agent must infer that this is the documentation/reference tool rather than a data-lookup tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_cam_timelineCam timelineARead-onlyIdempotentInspect
Archived still frames for a resort's webcams (or one cam) over the last 1–48 hours, as links with capture times, plus the newest storm frame on tape per cam. Only cams whose operator allows archiving appear; PeakCam captures every 6 hours. Use it for "what did it look like this morning" or "show me the last storm". Frames are never returned inline.
| Name | Required | Description | Default |
|---|---|---|---|
| slug | Yes | PeakCam resort slug, lowercase kebab-case, e.g. `breckenridge` or `ski-portillo`. Get it from search_resorts. | |
| camId | No | Optional: one cam's id from get_resort_cams; default is every archived cam at the resort. | |
| hours | No | Window, 1–48 hours. |
Output Schema
| Name | Required | Description |
|---|---|---|
| cams | Yes | |
| name | Yes | |
| note | Yes | |
| slug | Yes | |
| hours | Yes | |
| camCount | Yes | Cams with at least one frame in the result. |
| lastStorm | Yes | Newest storm frame across the resort, any age. |
| frameCount | Yes | |
| generatedAt | Yes | ISO-8601 UTC instant the result was generated. |
| canonicalUrl | Yes | |
| newestCapturedAt | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the read-only, idempotent, non-destructive profile, so the description is not carrying that burden. It adds genuinely useful behavioral facts beyond them: operator-level archiving eligibility, the 6-hour PeakCam capture cadence, and that frames are returned as links rather than inline. It omits pagination/rate-limit behavior, keeping it below a 5.
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?
Three dense sentences with no filler, and the core capability is front-loaded before the usage examples. The "never returned inline" caveat is important but placed last, slightly weakening the front-loading.
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?
An output schema exists, so return-value explanation is unnecessary, and annotations cover the safety profile. The description supplies the remaining agent-relevant context — archiving eligibility, capture cadence, and time-window bounds — so nothing needed to call it correctly is missing.
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 description coverage is 100%, so the schema already documents slug, camId, and hours with formats and defaults. The description restates the 1–48 hour window and the one-cam-vs-all-cams distinction but adds no syntax or semantic detail the schema lacks, making the baseline 3 appropriate.
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?
States a specific verb+resource (archived still frames for a resort's webcams), the temporal scope (1–48 hours), and the return form (links with capture times, plus the newest storm frame). It is clearly distinguishable from the sibling get_resort_cams, which covers live cams, without needing to open either schema.
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?
Gives concrete usage scenarios ("what did it look like this morning", "show me the last storm") and states an availability precondition (only archiving-allowed cams appear). It never explicitly routes the agent to the alternative for live footage, so it stops short of the when-not guidance a 5 would require.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_forecastResort forecastARead-onlyIdempotentInspect
Fourteen-day blended snow forecast for a resort: per day the median snowfall across the weather models that reach that day (ECMWF IFS, GFS, GEM, ICON, JMA, Météo-France, UKMO; NBM and HRRR added for US points), the 25th/75th percentile band as snowfallLoIn/snowfallHiIn, and modelCount so you can weigh a far-out two-model day against a near-term nine-model one. summary has next 48 h, 7- and 14-day totals and the peak day. US resorts also get the National Weather Service text narrative (periods), with its snow amounts replaced by the blend. Weather data by Open-Meteo.com (CC BY 4.0): quote the credit. available: false when no model run is stored yet.
| Name | Required | Description | Default |
|---|---|---|---|
| slug | Yes | PeakCam resort slug, lowercase kebab-case, e.g. `breckenridge` or `ski-portillo`. Get it from search_resorts. | |
| point | No | Which elevation's blend. Falls back to the other point with a note when the asked one has no runs. | summit |
Output Schema
| Name | Required | Description |
|---|---|---|
| days | Yes | Up to 14 blended days. |
| name | Yes | |
| note | Yes | |
| slug | Yes | |
| point | Yes | |
| models | Yes | |
| credits | Yes | |
| periods | Yes | NWS daily narrative for US resorts (up to 5 days); empty elsewhere or when NWS does not answer. |
| summary | Yes | |
| issuedAt | Yes | Newest model issue instant among the runs blended. |
| provider | Yes | `blend`: stored multi-model blend; `nws`: NWS narrative only, snow amounts are keyword estimates; `none`: nothing available. |
| available | Yes | |
| modelCount | Yes | Models contributing to the first day. |
| forecastUrl | Yes | The REST document with every model run. |
| generatedAt | Yes | ISO-8601 UTC instant the result was generated. |
| canonicalUrl | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover readOnly, idempotent and closed-world, but the description adds substantial non-redundant context: the model roster, what modelCount means for weighting confidence, the NWS narrative with amounts replaced by the blend, the required Open-Meteo attribution ('quote the credit'), and the available: false edge case when no run is stored. These are real obligations and failure modes an agent would not learn from the annotations.
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 purpose and horizon are front-loaded in the first clause, and each sentence carries information (blend method, band fields, summary contents, attribution, availability flag). The long parenthetical model enumeration is the only mildly verbose passage, though it does support interpreting modelCount.
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?
An output schema exists, so the description is not obliged to enumerate return values, yet it still explains the interpretation of the percentile band and modelCount, the summary block, the US-only periods narrative, and the empty-data case. Nothing an agent needs to call this correctly is missing.
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 description coverage is 100%, so both slug and point are already documented in the schema, including the enum values and the summit/base fallback. The description adds no additional parameter syntax or format guidance beyond that, so the baseline of 3 is appropriate.
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 opens with a specific verb, resource and horizon: a fourteen-day blended snow forecast for a resort. It also states the blend methodology (median across named models) and the derived fields, which clearly distinguishes it from get_snow_history, get_monthly_climatology and compare_models without needing the schema.
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?
Usage is only implied by the resource name: a forecast tool, so an agent can infer it is for upcoming snow rather than history or climatology. There is no explicit when-to-use/when-not statement or named alternative such as get_snow_history or compare_models. The only routing hint is the slug parameter's 'Get it from search_resorts', which is a dependency rather than a selection rule.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_leaderboardLeaderboardARead-onlyIdempotentInspect
Resorts ranked on one of four season boards: best-powder-this-week (measured new snow in the last 7 days), season-powder-days (days with ≥ 8 in since Oct 1), deepest-base (latest station or model depth) and season-snowfall (measured new snow since Oct 1), optionally within one state and measured-only. The season boards cover the Northern hemisphere. Answers a dated sentence, the rule in words and rows with source and station. Same data as https://www.peakcam.io/snow-report/{kind}.
| Name | Required | Description | Default |
|---|---|---|---|
| kind | Yes | Which board. | |
| limit | No | Rows to return, 1–50. | |
| state | No | US state or Canadian province code (`CO`, `UT`, `BC`), or for the Andes the country name PeakCam lists (`Chile`, `Argentina`). Case-insensitive. | |
| sourceOnly | No | `snotel` keeps only station-measured rows. |
Output Schema
| Name | Required | Description |
|---|---|---|
| asOf | Yes | |
| kind | Yes | |
| pool | Yes | Resorts considered after the filters. |
| rule | Yes | The ranking rule in words. |
| count | Yes | |
| title | Yes | |
| season | Yes | The Northern-hemisphere season the season-bound boards count from. |
| filters | Yes | |
| license | Yes | |
| pageUrl | Yes | |
| results | Yes | |
| sentence | Yes | The dated, quotable summary sentence. |
| weekStart | Yes | YYYY-MM-DD the 7-day window starts (best-powder-this-week). |
| attribution | Yes | |
| description | Yes | |
| generatedAt | Yes | |
| unavailable | Yes | True when the season aggregates could not be read; `results` is then empty. |
| totalMatching | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive/openWorld=false, so safety is covered. The description usefully adds behavior the annotations do not: the coverage restriction ('season boards cover the Northern hemisphere') and the return shape (dated sentence, rule in words, rows with source and station), plus a data-source URL.
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?
Front-loaded with the ranked resource and the four boards, and nearly every clause carries distinct information. It is a single dense paragraph, though, and the return-format and URL sentences could be trimmed or separated for faster scanning.
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?
An output schema exists, so return values need not be spelled out, and the description still summarizes them. It covers board definitions, hemisphere scope, state/source filters, and a reference link, leaving only minor gaps around pagination or ranking ties.
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 100 percent, so the baseline is 3, but the description genuinely extends `kind` beyond the schema's terse 'Which board' by defining what each board measures (new snow last 7 days, days ≥ 8 in since Oct 1, etc.) and clarifies the measured-only behavior of sourceOnly. It does not add meaning for `limit`.
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?
States a specific verb+resource (resorts ranked on season boards) and enumerates the four `kind` values with their exact measurement rules, so the agent can distinguish it from siblings like compare_resorts or get_season_stats without opening the schema.
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?
Usage is implied by the 'answers a dated sentence' framing and the nature of the boards, but no explicit when-to-use or when-not guidance is given, and no sibling tool (e.g. compare_resorts, find_powder) is named as the alternative path.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_monthly_climatologyMonthly climatologyARead-onlyIdempotentInspect
Average snowfall, snow days (≥ 1 in), depth and the biggest storm per calendar month at the resort's SNOTEL station, over the 30 most recent complete winters and, separately, the 10 most recent, with the recent decade as a percent of the 30-winter figure and a note when they differ by more than 10 %. Use it for "which month is snowiest", "how much does it usually snow in January". Resorts without a station normal answer available: false.
| Name | Required | Description | Default |
|---|---|---|---|
| slug | Yes | PeakCam resort slug, lowercase kebab-case, e.g. `breckenridge`. Get it from search_resorts. |
Output Schema
| Name | Required | Description |
|---|---|---|
| name | Yes | |
| note | Yes | |
| slug | Yes | |
| apiUrl | Yes | |
| months | Yes | In season order (October first in the North). |
| license | Yes | |
| pageUrl | Yes | |
| station | Yes | |
| available | Yes | False for resorts without a station normal; `months` is then empty. |
| attribution | Yes | |
| generatedAt | Yes | |
| canonicalUrl | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover safety (readOnly, idempotent, non-destructive), so the bar is lower; the description nonetheless adds real behavioral context: the 30-winter vs 10-winter breakdown, the recent-decade-as-percent-of-30 computation, the >10% divergence note, and an explicit no-station failure mode. It does not mention rate limits or data-availability windows, keeping it from a 5.
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?
Front-loads the returned metrics and scope, then use cases, with no filler. The first sentence is a dense run-on covering four metrics across two windows, which taxes readability but every clause conveys distinct information.
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?
Output schema exists, so return values need not be explained. The description covers what is computed, the comparison semantics, and the failure mode, leaving little an agent needs missing. Minor gaps around data latency are acceptable given the structured output.
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?
Single parameter with 100% schema description coverage, which already documents slug format and how to obtain it via search_resorts. The description adds nothing beyond the schema, so baseline 3 is correct.
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?
States a specific verb (compute/return) and resource (per-calendar-month climatology) with precise scope: snowfall, snow days ≥1in, depth, biggest storm, over 30 complete winters plus the recent 10. An agent can distinguish it from siblings like get_season_stats, get_snow_history, or get_percent_of_normal without opening a schema.
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?
Gives concrete use cases ('which month is snowiest', 'how much does it usually snow in January') and a failure condition ('Resorts without a station normal answer available: false'). No alternatives or siblings are named, so it stops short of full when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_opening_datesOpening datesARead-onlyIdempotentInspect
Season opening and closing dates with status (open / closed / unknown) for every resort, or those in one state/province, soonest opening first. Confirmed dates come from the resort; projected ones are third-party estimates.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Rows to return, 1–150. | |
| state | No | US state or Canadian province code (`CO`, `UT`, `BC`), or for the Andes the country name PeakCam lists (`Chile`, `Argentina`). Case-insensitive. |
Output Schema
| Name | Required | Description |
|---|---|---|
| asOf | Yes | YYYY-MM-DD (US Pacific) the statuses were evaluated for. |
| count | Yes | |
| filters | Yes | |
| resorts | Yes | |
| generatedAt | Yes | ISO-8601 UTC instant the result was generated. |
| totalMatching | Yes | Resorts that matched before `limit` was applied. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive, closed-world), so the bar is lower, and the description adds real context beyond them: data provenance distinguishing resort-confirmed dates from third-party projections, plus the possible values of the status field. It still does not state refresh cadence or how stale projected dates can be.
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?
Two sentences, both load-bearing: the first covers scope, status values and ordering; the second covers data provenance. Nothing is repeated and the most important scope information is front-loaded.
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?
An output schema exists, so return shape need not be described. Between the description (scope, ordering, status vocabulary, data provenance) and the fully documented 2-parameter schema, an agent has everything needed to call this 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?
Schema coverage is 100% and the schema already documents both parameters in detail, so the baseline is 3. The description adds the behavior of omitting `state` (returns every resort) and the output ordering ('soonest opening first'), neither of which the schema expresses; only `limit` receives no additional explanation.
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?
States a specific verb+resource (opening/closing dates per resort) plus the returned status values and sort order, which is far more than a restatement of the name. It does not explicitly name or contrast any sibling tool, so an agent infers distinctness from the resource alone rather than being routed.
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 scope clause ('for every resort, or those in one state/province') implies when to pass `state` versus leaving it out, which is genuine usage guidance. There is no when-not-to-use guidance and no mention of alternatives such as get_resort_conditions or get_forecast when the agent actually wants live status rather than season dates.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_percent_of_normalPercent of normalARead-onlyIdempotentInspect
SNOTEL-fed resorts ranked by snowpack relative to normal: snow water equivalent against the station's own 1991–2020 median for today's date, deepest first, optionally within one state. Only measured station readings qualify, inside the 10–300 % band and above 2 in of SWE; early-season noise is withheld, not ranked. Same data as https://www.peakcam.io/snow-report/percent-of-normal.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Rows to return, 1–50. | |
| state | No | US state or Canadian province code (`CO`, `UT`, `BC`), or for the Andes the country name PeakCam lists (`Chile`, `Argentina`). Case-insensitive. |
Output Schema
| Name | Required | Description |
|---|---|---|
| asOf | Yes | ISO instant of the newest report the ranking used. |
| rule | Yes | The publishable-value rule, in words. |
| count | Yes | |
| phase | Yes | `pre-season`/`early`: nothing rankable yet, see `sentence` for why. |
| filters | Yes | |
| pageUrl | Yes | |
| results | Yes | |
| sentence | Yes | The dated, quotable summary sentence. |
| generatedAt | Yes | ISO-8601 UTC instant the result was generated. |
| totalMatching | Yes | |
| stationFedCount | Yes | Resorts whose latest report is a SNOTEL reading (the pool). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, and the description adds substantial context beyond them: data source (SNOTEL station readings), the normal baseline used (1991–2020 median for today's date), inclusion thresholds (10–300% band, >2 in SWE), the sort order, and what is deliberately withheld from the ranking.
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?
Purpose and metric definition are front-loaded in the first clause, and the qualification rules are packed efficiently into the second. Dense with semicolons but no clearly wasted sentence; only the trailing marketing URL is dispensable.
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?
With an output schema present, the description needn't explain return values, and the annotations cover the safety profile. What remains an agent needs — metric definition, sort order, filtering thresholds, and geographic scoping — is all present.
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 100%, so both parameters are already documented in the schema; baseline 3 applies. The description only restates state scoping ('optionally within one state') and says nothing about the limit parameter or its default/ceiling, adding little beyond the 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?
States a specific verb+resource+ordering: 'SNOTEL-fed resorts ranked by snowpack relative to normal... deepest first, optionally within one state.' The definition of the metric (SWE vs the station's 1991–2020 median for today's date) distinguishes it clearly from siblings like get_snow_history and compare_resorts.
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?
Gives clear decision context: measurement-based ranking, optional single-state scoping, and explicit exclusion rules ('early-season noise is withheld, not ranked') that tell the agent when results will be thin or empty. It does not name an alternative sibling (e.g. compare_resorts, get_snow_history) or state when-not to use it, so it stops short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_resort_camsResort webcamsARead-onlyIdempotentInspect
The resort's webcams as links: PeakCam page URL, the operator's stream or page URL, a still-image URL when one exists, and health (live / down / unchecked, from PeakCam's probe, not proof of a live broadcast). Frames are never returned inline.
| Name | Required | Description | Default |
|---|---|---|---|
| slug | Yes | PeakCam resort slug, lowercase kebab-case, e.g. `breckenridge` or `ski-portillo`. Get it from search_resorts. |
Output Schema
| Name | Required | Description |
|---|---|---|
| cams | Yes | |
| name | Yes | |
| slug | Yes | |
| license | Yes | |
| updatedAt | Yes | |
| attribution | Yes | |
| canonicalUrl | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, so the bar is lower, and the description still adds real value: it defines the health field's domain (live/down/unchecked) and warns it comes from PeakCam's probe and is 'not proof of a live broadcast.' That caveat prevents a real misinterpretation. It stops short of describing caching, refresh cadence, or behavior when a cam is missing.
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?
A single dense sentence front-loads the resource and then enumerates the return fields in a compact colon-separated list. Every clause carries information; only the parenthetical health caveat slightly interrupts the flow.
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?
With an output schema present, the description is not obliged to explain return values, yet it usefully characterizes them anyway and clarifies the health semantics. For a single-parameter read-only lookup, nothing critical is missing; only explicit routing to the timeline/timelapse siblings would improve it.
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 description coverage is 100%, and the single slug parameter is fully documented in the schema (kebab-case format plus the search_resorts pointer). The description adds no parameter detail of its own, so the baseline 3 applies.
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 names the resource (the resort's webcams) and enumerates exactly what is returned: PeakCam page URL, operator stream/page URL, still-image URL, and a health flag. That specificity lets an agent distinguish it from siblings like get_cam_timeline and get_timelapses, though it never names those alternatives explicitly.
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?
Usage is only implied. The clause 'Frames are never returned inline' hints that an agent wanting actual imagery must go elsewhere, but no sibling tool or condition is named. There is no explicit statement of when to prefer this over get_cam_timeline or get_timelapses.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_resort_conditionsResort conditionsARead-onlyIdempotentInspect
The latest snow report for one resort with provenance, inside the conditions contract v2 envelope: data.status is the derived operating status (OPEN, CLOSED_TODAY, PRE_SEASON, OFF_SEASON or UNKNOWN; OPEN only on a fresh operator lift feed or a resort-confirmed opening date, never by default) with reasons; every field in data (base depth measured and operator-reported, new snow 24 h / 48 h, SWE, percent of normal, lifts and runs open / total, surface, snow quality, temperature, wind, blended 48-hour forecast, season dates) is {value, source, observedAt, confidence, freshness: {tier, ageHours}}; depthDisagreement is set when the station and the operator differ by more than 30 % (quote the measured value); sentence is a dated line to quote. The classic Resort document (snow, season, cams, profile, measuredNow) rides alongside for compatibility. Use it for "is X open today" as well as "what are conditions at X". Sources: snotel = measured at a USDA NRCS SNOTEL station near the resort (station elevation, not the summit), open_meteo = weather-model estimate for resorts without a station.
| Name | Required | Description | Default |
|---|---|---|---|
| slug | Yes | PeakCam resort slug, lowercase kebab-case, e.g. `breckenridge` or `ski-portillo`. Get it from search_resorts. |
Output Schema
| Name | Required | Description |
|---|---|---|
| cams | Yes | |
| data | Yes | |
| meta | Yes | |
| name | Yes | |
| slug | Yes | |
| snow | Yes | Null when the resort has never had a snow report. |
| score | No | Today's 0–100 Snow Score with components (P7). Null when the scorer has not written a row at most 3 days old; absent only when the score table is not served. |
| apiUrl | Yes | |
| season | Yes | |
| license | Yes | URL of the terms that govern reuse. |
| profile | Yes | |
| forecast | No | Headline numbers from the blended 14-day forecast (summit point when one exists). Null when no run is current; absent on list and compare rows. The full daily blend and every model run are at `/resorts/{slug}/forecast`. |
| location | Yes | |
| sentence | Yes | A dated, source-labelled status sentence that can be quoted verbatim. |
| stations | No | Observation stations serving the resort, once the station layer is live. |
| schemaUrl | Yes | The JSON Schema this document validates against. |
| updatedAt | Yes | Newest instant among the snow report and cam checks/captures. |
| websiteUrl | Yes | |
| attribution | Yes | |
| measuredNow | No | Latest observation per station, once the station layer is live. |
| canonicalUrl | Yes | The resort's PeakCam page. Cite this. |
| schemaVersion | Yes | Contract version; the schema file name carries the major. |
| forecastScores | No | Per-model verification at this resort over 90 days, ranked; empty until the scorer has measured days. Detail at `/resorts/{slug}/forecast-accuracy`. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish the safe read-only profile, and the description adds substantial behavioral detail beyond them: the OPEN-only-on-fresh-feed rule, the meaning of UNKNOWN, the 30% depthDisagreement trigger, what `sentence` is for, and the distinction between snotel (measured, station elevation not summit) and open_meteo (model estimate) sources.
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 first sentence front-loads the purpose well, but the body enumerates nearly every field inside `data` and the legacy Resort document even though an output schema exists — that detail is largely duplicated in structured data. Dense parenthetical packing makes it heavier than it needs to be.
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?
For a one-parameter, read-only tool with a full output schema and covering annotations, an agent has everything needed to call it correctly, and the status/source semantics are genuinely useful. It over-delivers on return-value detail rather than leaving gaps, so completeness is high but not perfectly matched to what the schema already provides.
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?
The single `slug` parameter is fully documented in the schema (100% coverage) including kebab-case format and where to obtain it. The description adds no parameter-specific guidance, so it relies on the schema baseline of 3; the source-type explanation is about returned data, not the input.
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?
States a specific verb and resource ('latest snow report for one resort'), plus the envelope shape it returns (conditions contract v2). It is clearly distinguishable from siblings like get_resort_profile, get_snow_history, or compare_resorts because it is scoped to a single resort's current conditions.
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 names two triggering questions: "is X open today" and "what are conditions at X", and tells the agent where the required slug comes from (search_resorts). It does not name alternative siblings (e.g., get_forecast for future outlook, get_snow_history for past), so it stops short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_resort_profileResort profileARead-onlyIdempotentInspect
Who and where a resort is, without the snow numbers: location and elevations, website and social links, PeakCam's cam page, the SNOTEL station its numbers come from (if any), season status, cam counts, and every URL PeakCam publishes for it (page, JSON, markdown, Atom feed, state hub). Use get_resort_conditions for today's snow.
| Name | Required | Description | Default |
|---|---|---|---|
| slug | Yes | PeakCam resort slug, lowercase kebab-case, e.g. `breckenridge` or `ski-portillo`. Get it from search_resorts. |
Output Schema
| Name | Required | Description |
|---|---|---|
| name | Yes | |
| slug | Yes | |
| urls | Yes | |
| season | Yes | |
| socials | Yes | |
| station | Yes | The NRCS station PeakCam reads for this resort; null means model estimates. |
| camCount | Yes | |
| location | Yes | |
| camPageUrl | Yes | The operator's own webcam page, when PeakCam records one. |
| dataSource | Yes | Source of the latest snow report, so you know which label to use. |
| websiteUrl | Yes | The operator's site. |
| generatedAt | Yes | ISO-8601 UTC instant the result was generated. |
| canonicalUrl | Yes | The resort's PeakCam page. Cite this. |
| liveCamCount | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, non-destructive, and closed-world, so the safety profile is covered. The description adds genuine behavioral context beyond them: it signals that the SNOTEL station may be absent ('if any') and that the response includes a full set of published URL variants. It does not mention auth or rate limits, which is a minor gap for a read tool.
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 scope statement is front-loaded and the routing sentence is short and purposeful. The long mid-sentence enumeration is dense but every listed field is informative for tool selection, so it mostly earns its place.
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?
With an output schema present, the description need not explain return values, yet it usefully summarizes them for selection purposes. Combined with full annotation coverage and a 100%-documented schema, an agent has everything needed to call it correctly; only operational details like auth or rate limits are absent.
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 description coverage is 100% and the single slug parameter is fully documented in the schema, including format and the search_resorts sourcing hint. The description adds no parameter-level detail, so the baseline 3 applies.
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 names a specific resource (resort profile) and enumerates exactly what it contains: location, elevations, links, SNOTEL station, season status, cam counts, and published URLs. It explicitly carves out the scope it does NOT cover ('without the snow numbers'), which cleanly separates it from get_resort_conditions.
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?
It routes the agent explicitly: 'Use get_resort_conditions for today's snow,' giving both the alternative and the condition that selects it. The negative scoping phrase also tells the agent when not to reach for this tool for snow data, so no inference is required.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_scoreSnow ScoreARead-onlyIdempotentInspect
PeakCam's 0–100 Snow Score for one resort, scored once a day by a fixed formula (scoredBy is always algorithmic): today carries the score, its four-tier rating (great ≥ 75, good ≥ 55, fair ≥ 35, else poor; the same words as the conditions rating), a dated tagline to quote and five components, each with points, max, a one-line basis and its source: depth vs the station's 1991–2020 normal (30), new snow over the last 7 days (25), the blended 7-day forecast (20), snow quality from days since snow, the 3-day high and the surface tags (15), and the operating status (10). history is one point per scored day over the last 30 days. Use it for "how good is X right now and why", "score X out of 100", "is X better than last week"; for a ranking use find_powder, compare_resorts or /api/v1/snow-report?sort=score. available: false before the first scoring run.
| Name | Required | Description | Default |
|---|---|---|---|
| slug | Yes | PeakCam resort slug, lowercase kebab-case, e.g. `breckenridge` or `ski-portillo`. Get it from search_resorts. |
Output Schema
| Name | Required | Description |
|---|---|---|
| days | Yes | The history window, days. |
| name | Yes | |
| slug | Yes | |
| today | Yes | The newest score at most 3 days old, else null. |
| apiUrl | Yes | This document. |
| ladder | Yes | Score at or above each cutoff earns the label; below `fair` is `poor`. |
| history | Yes | One point per scored day over the trailing window, oldest first. |
| license | Yes | |
| pageUrl | Yes | Where the score ring and sparkline render. |
| version | Yes | |
| weights | Yes | |
| scoredBy | Yes | |
| sentence | Yes | The dated tagline, or why there is no score. |
| available | Yes | False when the scorer has not written a row for this resort yet (or the table is not served). |
| attribution | Yes | |
| generatedAt | Yes | |
| canonicalUrl | Yes | |
| methodologyUrl | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare this is a safe, idempotent read, and the description adds substantial context beyond them: the daily scoring cadence, fixed formula with scoredBy always 'algorithmic', the tier thresholds, the five weighted components, and the 'available: false before the first scoring run' edge case. That is rich behavioral disclosure.
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?
Front-loaded with the core definition, then tier thresholds, component weights, and finally use cases. It is a single dense paragraph but nearly every clause carries distinct information; slightly heavy for the size but not wasteful.
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?
With an output schema present, the description needn't detail return values, yet it usefully previews the score/history structure and the unavailability state. For a one-param read tool, nothing an agent needs to call it correctly is missing.
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 100% with a single documented slug parameter, so the schema carries the parameter burden. The description adds no syntax or format detail beyond what the schema provides (kebab-case, from search_resorts), so the baseline 3 is appropriate.
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?
States a specific verb+resource: PeakCam's 0–100 Snow Score for one resort, scored once daily by a fixed formula, and explicitly distinguishes itself from ranking tools (find_powder, compare_resorts). An agent can tell exactly what value this returns without opening a schema.
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?
Gives explicit trigger phrases ('how good is X right now and why', 'score X out of 100', 'is X better than last week') and names the alternatives for a ranking use case (find_powder, compare_resorts, /api/v1/snow-report?sort=score). When-to-use and when-to-use-something-else are both covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_season_statsSeason statsARead-onlyIdempotentInspect
Season-to-date for one resort from PeakCam's own daily station record: measured snowfall since the season start (daily new snow = the positive change in station depth, a floor on what fell), days measured, snow days, powder days (8 in or more, the alert threshold), current and deepest base, percent of the 30-winter normal to this day and of the recent decade (with a baselineNote when they disagree by more than 10 %), the same day last year, a 7-day trend and a dated sentence to quote. Use it for "how is the season going", "is this a good year", "how does it compare with last year".
| Name | Required | Description | Default |
|---|---|---|---|
| slug | Yes | PeakCam resort slug, lowercase kebab-case, e.g. `breckenridge`. Get it from search_resorts. |
Output Schema
| Name | Required | Description |
|---|---|---|
| asOf | Yes | YYYY-MM-DD of the newest daily reading this season. |
| name | Yes | |
| slug | Yes | |
| trend | Yes | |
| apiUrl | Yes | |
| season | Yes | |
| source | Yes | |
| license | Yes | |
| pageUrl | Yes | |
| station | Yes | |
| lastYear | Yes | |
| sentence | Yes | A dated sentence that can be quoted verbatim. |
| snowDays | Yes | |
| available | Yes | |
| hemisphere | Yes | |
| powderDays | Yes | |
| attribution | Yes | |
| dayOfSeason | Yes | |
| deepestBase | Yes | |
| generatedAt | Yes | |
| canonicalUrl | Yes | |
| daysMeasured | Yes | |
| currentBaseIn | Yes | |
| seasonToDateIn | Yes | |
| percentOfNormal | Yes | |
| powderDayThresholdIn | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (which only establish a safe, idempotent read), the description discloses methodology and caveats: daily new snow is the positive change in station depth and is 'a floor on what fell', powder days use the 8-inch alert threshold, and baselineNote appears when the 30-winter and decade normals disagree by more than 10%. This is exactly the behavioral context an agent needs to interpret the numbers honestly.
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?
Front-loaded with what it returns and packed densely; the long enumerative sentence is justified by the many distinct metrics, and the usage sentence is short. It is a run-on, but virtually every clause carries information, so little is wasted.
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?
Although an output schema exists and return values could be left to it, the description goes further and explains metric definitions, comparison baselines, and the trend/quotable sentence, which is complete for a single-resort read tool with all safety traits already covered by annotations.
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?
There is a single slug parameter and schema coverage is 100%, with the schema itself documenting the format and pointing to search_resorts. The description adds no additional parameter meaning, so the baseline of 3 applies.
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 names the exact resource ('Season-to-date for one resort'), the data source ('PeakCam's own daily station record'), and enumerates the specific metrics returned, so an agent knows precisely what it retrieves. It does not, however, explicitly differentiate itself from close siblings such as get_snow_history, get_percent_of_normal, or get_monthly_climatology, leaving the agent to infer the boundary.
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?
It gives concrete trigger questions ('how is the season going', 'is this a good year', 'how does it compare with last year') that map cleanly to intent. It stops short of naming alternatives or exclusions, so the routing against get_percent_of_normal / get_snow_history is not spelled out.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_snow_historySnow historyARead-onlyIdempotentInspect
Daily snow depth, snow water equivalent, precipitation accumulation and temperatures for the last 1–30 days at the resort's station (SNOTEL where there is one, Open-Meteo model otherwise), newest first. Use it for "how has the base changed this week" questions. Pass season (2024-25, or current) for a whole season's daily depth and new-snow rows instead of the last N days; get_season_stats summarises a season.
| Name | Required | Description | Default |
|---|---|---|---|
| days | No | Days back, 1–30. Ignored when `season` is set. | |
| slug | Yes | PeakCam resort slug, lowercase kebab-case, e.g. `breckenridge` or `ski-portillo`. Get it from search_resorts. | |
| season | No | A season label (`2024-25` for the Northern water year, `2026` for an Andes resort) or `current`: returns every daily row of that season, oldest first, with daily new snow. |
Output Schema
| Name | Required | Description |
|---|---|---|
| days | Yes | |
| name | Yes | |
| rows | Yes | |
| slug | Yes | |
| count | Yes | |
| season | Yes | The season label when `season` was asked for; null for a last-N-days read. |
| source | Yes | |
| station | Yes | |
| generatedAt | Yes | ISO-8601 UTC instant the result was generated. |
| canonicalUrl | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnlyHint, idempotentHint, destructiveHint=false), so the description's added value is the station provenance (SNOTEL where available, otherwise Open-Meteo model) and the ordering difference between the days view (newest first) and the season view (oldest first). These are real behavioral details not derivable from the annotations.
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?
Dense but well-structured: the payload is front-loaded, then the usage case, then the parameter/sibling routing. Every sentence earns its place, though the parenthetical source detail and the routing clause make it slightly long for the amount of schema support available.
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?
With an output schema present (so return values need no prose) and annotations covering the safety profile, the description supplies the remaining essentials: what data, from which source, in what order, and how the season path differs. Nothing an agent needs to call it correctly is missing.
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 100%, so the baseline is 3, but the description goes further by explaining the days/season interaction (season returns every daily row of the season with new snow, superseding the last-N-days window) rather than merely restating the 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?
States a specific resource (daily snow depth, SWE, precipitation, temperatures) with explicit scope (last 1–30 days at the resort's station), data provenance (SNOTEL vs Open-Meteo model), and ordering (newest first). An agent can distinguish this from get_season_stats and get_forecast without opening any schema.
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?
Gives a concrete when-to-use case ("how has the base changed this week") and routes the agent to the right sibling for season summaries (get_season_stats) and to the `season` parameter for whole-season rows. It stops short of an explicit when-not (e.g. vs. get_forecast for future snow), so it is clear but not fully closed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_stationsNearby stationsARead-onlyIdempotentInspect
What the instruments near one resort measured, by elevation band (summit / mid / base): up to three stations within 25 km with the network named (SNOTEL, GHCN-Daily, NWS, BC ASWS, ECCC), elevation, distance, the time of the reading and its age, snow depth, new snow, SWE, temperature and wind. Daily networks carry depth; hourly ones carry temperature and wind. Use it for "what is it like at the top right now" and "how old is that number" questions; the snow report itself comes from get_resort_conditions.
| Name | Required | Description | Default |
|---|---|---|---|
| slug | Yes | PeakCam resort slug, lowercase kebab-case, e.g. `breckenridge` or `ski-portillo`. Get it from search_resorts. |
Output Schema
| Name | Required | Description |
|---|---|---|
| name | Yes | |
| slug | Yes | |
| count | Yes | |
| sources | Yes | |
| stations | Yes | |
| available | Yes | False when the station layer is not populated for this deployment yet. |
| generatedAt | Yes | ISO-8601 UTC instant the result was generated. |
| measuredNow | Yes | |
| canonicalUrl | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only/idempotent/closed-world, so the bar is low, yet the description adds rich operational context: the 3-station and 25 km caps, the elevation-band grouping, the named networks, and the key data-availability rule that daily networks carry depth while hourly ones carry temperature and wind.
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?
Front-loads the core payload (what is measured, scope, bands) before the data-availability rule and usage examples. It is dense but every clause carries operational meaning; slightly long, which keeps it from a 5.
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?
With an output schema present, return values need no explanation, and the description covers scope, limits, fields, network behavior, and sibling routing. An agent has everything needed to call it 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?
Single parameter with 100% schema description coverage that fully documents the slug format and its source (search_resorts). The description adds no slug detail beyond the schema, so baseline 3 is appropriate.
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?
States a specific verb (what instruments measured) and resource (nearby stations) with precise scope: up to three stations within 25 km, split by elevation band. Explicitly distinguishes itself from get_resort_conditions, so an agent can tell them apart without opening schemas.
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?
Names the exact questions it answers ("what is it like at the top right now", "how old is that number") and routes the alternative use case — the snow report — to get_resort_conditions. This is explicit when-to-use plus alternative routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_timelapsesTimelapsesARead-onlyIdempotentInspect
Rendered timelapse clips for a resort's webcams (or one cam), as links: the rolling 24-hour MP4 per cam (H.264, 7 fps, 720p max, at most 3 MB, re-rendered every 6 hours from PeakCam's still archive) with its poster JPEG and frame bounds, plus storm reels (rendered while the resort's measured 24 h new snow is 8 in or more, from the first frame after the last dry day, capped at 72 h; one per storm day, kept a year). Only cams whose operator allows archiving have clips. Use it for "show me the last 24 hours" or "show me the last storm" questions; get_cam_timeline returns the individual frames. Media is never returned inline.
| Name | Required | Description | Default |
|---|---|---|---|
| slug | Yes | PeakCam resort slug, lowercase kebab-case, e.g. `breckenridge` or `ski-portillo`. Get it from search_resorts. | |
| camId | No | Optional: one cam's id from get_resort_cams; default is every cam with a clip. |
Output Schema
| Name | Required | Description |
|---|---|---|
| cams | Yes | Only cams with at least one clip, in the resort's cam order. |
| name | Yes | |
| note | Yes | |
| slug | Yes | |
| license | Yes | |
| available | Yes | False when the clip table is not served by this deployment yet. |
| clipCount | Yes | |
| lastStorm | Yes | The newest storm reel across the resort's cams. |
| updatedAt | Yes | |
| webcamsUrl | Yes | The resort's webcams page, where the clips play. |
| attribution | Yes | |
| canonicalUrl | Yes | |
| newestRenderedAt | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover safety (readOnly, idempotent, non-destructive), but the description adds substantial behavior beyond them: render cadence (every 6 hours), encoding specs (H.264, 7 fps, 720p, ≤3 MB), storm-reel trigger (>8 in new snow), retention (1 year), the operator-archiving restriction, and the critical note that media is never returned inline.
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?
Purpose and the 24-hour clip are front-loaded, and most clauses earn their place (cadence, storm criteria, retention, archiving restriction). The single dense paragraph packs a lot of encoding minutiae (7 fps, 720p, 3 MB) that is useful but borderline for a selection-time description.
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?
With an output schema present, return-value shape needn't be explained, and the description still covers what a caller needs: links vs. inline media, poster JPEG, frame bounds, and the archiving caveat. Complete for a read-only lookup tool.
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 description coverage is 100%, so both slug and camId are already documented, including the 'default is every cam' behavior. The description's '(or one cam)' phrasing mirrors the schema without adding new semantics, so baseline 3 is appropriate.
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?
States a specific verb+resource ('Rendered timelapse clips for a resort's webcams') and immediately distinguishes itself from the sibling get_cam_timeline ('returns the individual frames'). An agent can tell the two apart without opening either schema.
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?
Gives explicit trigger phrases ('show me the last 24 hours' or 'show me the last storm') and names the alternative tool (get_cam_timeline) for the frame-level case. Nothing about when to select this vs. a sibling is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_regionsList regionsARead-onlyIdempotentInspect
Every state, province and country PeakCam covers, with resort, reporting, measured (SNOTEL) and cam counts and the hub page URL. Call it to learn the valid state values for find_powder, get_opening_dates and get_percent_of_normal, or to answer "where does PeakCam have data".
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| regions | Yes | Most resorts first. |
| countries | Yes | |
| generatedAt | Yes | ISO-8601 UTC instant the result was generated. |
| totalResorts | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, openWorldHint=false and destructiveHint=false, so safety and idempotency are covered structurally. The description adds real context beyond that: the geographic scope (states, provinces, countries) and the specific counts returned, which is what an agent needs to judge whether calling it is worthwhile. It does not restate the annotated safety traits, so no contradiction.
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?
Two sentences, front-loaded with what the tool returns, followed by the concrete reason to call it. Every clause carries information; there is no filler or restatement of the title.
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?
For a zero-parameter, read-only discovery tool with an output schema, the description supplies everything an agent needs: the scope of the result set, the fields returned, and the downstream tools that consume the returned `state` values. Nothing material is missing.
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?
The tool takes zero parameters, so there is no per-parameter semantics to explain and the baseline of 4 applies. The description does add meaning about the shape of the result (counts per region plus hub URL) even though the output schema already documents it.
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?
States a specific resource (every state, province and country PeakCam covers) and enumerates exactly what it returns: resort, reporting, SNOTEL and cam counts plus the hub page URL. That granularity lets an agent distinguish it from sibling lookups like search_resorts or get_resort_profile without opening a schema.
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?
Gives an explicit trigger ('call it to learn the valid `state` values for find_powder, get_opening_dates and get_percent_of_normal') and a natural-language use case ('where does PeakCam have data'). It names the three dependent siblings by name, so the routing decision is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_resortsSearch resortsARead-onlyIdempotentInspect
Find PeakCam resorts by name (or part of one, or a region) and get their slugs with a one-line snow summary each. Call this first when the user names a resort; then use the slug with the other tools. Covers about 300 resorts in the US, Canada, Chile and Argentina.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Rows to return, 1–20. | |
| query | Yes | Resort name or fragment, e.g. `vail`, `big sky`, `portillo`, `tahoe`. Also matches region names. | |
| state | No | US state or Canadian province code (`CO`, `UT`, `BC`), or for the Andes the country name PeakCam lists (`Chile`, `Argentina`). Case-insensitive. | |
| country | No | ISO 3166-1 alpha-2 country code: `US`, `CA`, `CL` or `AR`. |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | Yes | |
| query | Yes | |
| resorts | Yes | |
| generatedAt | Yes | ISO-8601 UTC instant the result was generated. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only, idempotent, non-destructive, closed-world, so the safety profile is covered. The description adds useful scope context the annotations cannot convey: ~300 resorts and the four countries covered, plus the fact that matching is fuzzy (name fragment or region). No rate-limit or pagination behavior, but little is left ambiguous.
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?
Two sentences, front-loaded with the action and return value, followed by the workflow instruction and the coverage scope. No filler; every clause carries information.
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?
With an output schema present, the description needn't explain return shape, and it still summarizes the snow-summary payload. Annotations cover safety, schema covers all params, and the description adds scope plus the call-order cue — nothing an agent needs to invoke this correctly is missing.
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 description coverage is 100%, so all four parameters (query, limit, state, country) are already documented with examples and ranges. The description restates the fuzzy-name/region matching that the query param already documents, adding no new syntax or format guidance. Baseline 3 applies.
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?
States a specific verb and resource ('Find PeakCam resorts by name... and get their slugs') plus the returned payload ('one-line snow summary each'). This distinguishes it from siblings like list_regions (browsing) and get_resort_profile (detail by slug).
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?
Explicit sequencing: 'Call this first when the user names a resort; then use the slug with the other tools' — this is real routing guidance for the multi-tool workflow. It doesn't name an alternative for the case where the user does NOT name a resort (list_regions would be the natural fallback), so it stops short of full when/when-not coverage.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
5 tool updates
- Changed
compare_resorts2 fields changed- changed
Output schema / properties / resorts / items / properties / score / anyOfPrevious value: -[ - { - "additionalProperties": false, - "properties": { - "components": { - "additionalProperties": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ] - }, - "propertyNames": { - "type": "string" - }, - "type": "object" - }, - "date": { - "description": "YYYY-MM-DD the score is for.", - "type": "string" - }, - "rating": { - "anyOf": [ - { - "enum": [ - "great", - "good", - "fair", - "poor" - ], - "type": "string" - }, - { - "type": "null" - } - ] - }, - "score": { - "maximum": 100, - "minimum": 0, - "type": "integer" - }, - "scoredBy": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Scorer version, e.g. `score-v1`." - } - }, - "required": [ - "date", - "score", - "rating", - "components", - "scoredBy" - ], - "type": "object" - }, - { - "type": "null" - } -]New value: +[ + { + "additionalProperties": false, + "properties": { + "components": { + "additionalProperties": false, + "properties": { + "depthVsNormal": { + "additionalProperties": false, + "description": "30: snowpack against the station's 1991–2020 median (SWE); without a normal, base depth on a fixed scale capped at 27.", + "properties": { + "basis": { + "description": "One line saying what the points rest on, quotable as is.", + "type": "string" + }, + "max": { + "description": "The component's weight; the five maximums add to 100.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "points": { + "description": "Points earned, one decimal.", + "minimum": 0, + "type": "number" + }, + "source": { + "enum": [ + "snotel", + "model", + "operator", + "profile", + "derived", + "none" + ], + "type": "string" + } + }, + "required": [ + "points", + "max", + "basis", + "source" + ], + "type": "object" + }, + "forecast7d": { + "additionalProperties": false, + "description": "20: the blended next-7-day forecast total (20 in is full marks).", + "properties": { + "basis": { + "description": "One line saying what the points rest on, quotable as is.", + "type": "string" + }, + "max": { + "description": "The component's weight; the five maximums add to 100.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "points": { + "description": "Points earned, one decimal.", + "minimum": 0, + "type": "number" + }, + "source": { + "enum": [ + "snotel", + "model", + "operator", + "profile", + "derived", + "none" + ], + "type": "string" + } + }, + "required": [ + "points", + "max", + "basis", + "source" + ], + "type": "object" + }, + "operatingStatus": { + "additionalProperties": false, + "description": "10: OPEN full, PRE_SEASON and CLOSED_TODAY half, OFF_SEASON and UNKNOWN none.", + "properties": { + "basis": { + "description": "One line saying what the points rest on, quotable as is.", + "type": "string" + }, + "max": { + "description": "The component's weight; the five maximums add to 100.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "points": { + "description": "Points earned, one decimal.", + "minimum": 0, + "type": "number" + }, + "source": { + "enum": [ + "snotel", + "model", + "operator", + "profile", + "derived", + "none" + ], + "type": "string" + } + }, + "required": [ + "points", + "max", + "basis", + "source" + ], + "type": "object" + }, + "recentSnow7d": { + "additionalProperties": false, + "description": "25: measured or modelled new snow over the last 7 days (24 in is full marks).", + "properties": { + "basis": { + "description": "One line saying what the points rest on, quotable as is.", + "type": "string" + }, + "max": { + "description": "The component's weight; the five maximums add to 100.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "points": { + "description": "Points earned, one decimal.", + "minimum": 0, + "type": "number" + }, + "source": { + "enum": [ + "snotel", + "model", + "operator", + "profile", + "derived", + "none" + ], + "type": "string" + } + }, + "required": [ + "points", + "max", + "basis", + "source" + ], + "type": "object" + }, + "snowQuality": { + "additionalProperties": false, + "description": "15: days since the last snow day × the 3-day high temperature × the engine's surface tags.", + "properties": { + "basis": { + "description": "One line saying what the points rest on, quotable as is.", + "type": "string" + }, + "max": { + "description": "The component's weight; the five maximums add to 100.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "points": { + "description": "Points earned, one decimal.", + "minimum": 0, + "type": "number" + }, + "source": { + "enum": [ + "snotel", + "model", + "operator", + "profile", + "derived", + "none" + ], + "type": "string" + } + }, + "required": [ + "points", + "max", + "basis", + "source" + ], + "type": "object" + } + }, + "required": [ + "depthVsNormal", + "recentSnow7d", + "forecast7d", + "snowQuality", + "operatingStatus" + ], + "type": "object" + }, + "date": { + "description": "YYYY-MM-DD the score is for (Mountain-time day of the scoring run).", + "type": "string" + }, + "rating": { + "description": "The score's four-tier label: great ≥ 75, good ≥ 55, fair ≥ 35, else poor.", + "enum": [ + "great", + "good", + "fair", + "poor" + ], + "type": "string" + }, + "score": { + "maximum": 100, + "minimum": 0, + "type": "integer" + }, + "scoredBy": { + "const": "algorithmic", + "description": "Always `algorithmic`: a fixed function of measured and modelled inputs, never an editorial call.", + "type": "string" + }, + "tagline": { + "description": "Dated sentence to quote: the score, its rating and the components strongest first.", + "type": "string" + }, + "version": { + "description": "Formula version, e.g. `score-v1`; a change re-scores the history.", + "type": "string" + } + }, + "required": [ + "date", + "score", + "rating", + "tagline", + "components", + "scoredBy", + "version" + ], + "type": "object" + }, + { + "type": "null" + } +] - changed
Output schema / properties / resorts / items / properties / score / descriptionPrevious value: -"Today's 0–100 score, once the scorer is live."New value: +"Today's 0–100 Snow Score with components (P7). Null when the scorer has not written a row at most 3 days old; absent only when the score table is not served."
- Changed
find_powder1 field changed- added
Output schema / properties / results / items / properties / scoreAdded value: +{ + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "date": { + "description": "YYYY-MM-DD.", + "type": "string" + }, + "rating": { + "enum": [ + "great", + "good", + "fair", + "poor" + ], + "type": "string" + }, + "score": { + "maximum": 100, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "date", + "score", + "rating" + ], + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Today's Snow Score (P7), when the caller loaded the score index." +}
- Changed
get_resort_conditions2 fields changed- changed
Output schema / properties / score / anyOfPrevious value: -[ - { - "additionalProperties": false, - "properties": { - "components": { - "additionalProperties": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ] - }, - "propertyNames": { - "type": "string" - }, - "type": "object" - }, - "date": { - "description": "YYYY-MM-DD the score is for.", - "type": "string" - }, - "rating": { - "anyOf": [ - { - "enum": [ - "great", - "good", - "fair", - "poor" - ], - "type": "string" - }, - { - "type": "null" - } - ] - }, - "score": { - "maximum": 100, - "minimum": 0, - "type": "integer" - }, - "scoredBy": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Scorer version, e.g. `score-v1`." - } - }, - "required": [ - "date", - "score", - "rating", - "components", - "scoredBy" - ], - "type": "object" - }, - { - "type": "null" - } -]New value: +[ + { + "additionalProperties": false, + "properties": { + "components": { + "additionalProperties": false, + "properties": { + "depthVsNormal": { + "additionalProperties": false, + "description": "30: snowpack against the station's 1991–2020 median (SWE); without a normal, base depth on a fixed scale capped at 27.", + "properties": { + "basis": { + "description": "One line saying what the points rest on, quotable as is.", + "type": "string" + }, + "max": { + "description": "The component's weight; the five maximums add to 100.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "points": { + "description": "Points earned, one decimal.", + "minimum": 0, + "type": "number" + }, + "source": { + "enum": [ + "snotel", + "model", + "operator", + "profile", + "derived", + "none" + ], + "type": "string" + } + }, + "required": [ + "points", + "max", + "basis", + "source" + ], + "type": "object" + }, + "forecast7d": { + "additionalProperties": false, + "description": "20: the blended next-7-day forecast total (20 in is full marks).", + "properties": { + "basis": { + "description": "One line saying what the points rest on, quotable as is.", + "type": "string" + }, + "max": { + "description": "The component's weight; the five maximums add to 100.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "points": { + "description": "Points earned, one decimal.", + "minimum": 0, + "type": "number" + }, + "source": { + "enum": [ + "snotel", + "model", + "operator", + "profile", + "derived", + "none" + ], + "type": "string" + } + }, + "required": [ + "points", + "max", + "basis", + "source" + ], + "type": "object" + }, + "operatingStatus": { + "additionalProperties": false, + "description": "10: OPEN full, PRE_SEASON and CLOSED_TODAY half, OFF_SEASON and UNKNOWN none.", + "properties": { + "basis": { + "description": "One line saying what the points rest on, quotable as is.", + "type": "string" + }, + "max": { + "description": "The component's weight; the five maximums add to 100.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "points": { + "description": "Points earned, one decimal.", + "minimum": 0, + "type": "number" + }, + "source": { + "enum": [ + "snotel", + "model", + "operator", + "profile", + "derived", + "none" + ], + "type": "string" + } + }, + "required": [ + "points", + "max", + "basis", + "source" + ], + "type": "object" + }, + "recentSnow7d": { + "additionalProperties": false, + "description": "25: measured or modelled new snow over the last 7 days (24 in is full marks).", + "properties": { + "basis": { + "description": "One line saying what the points rest on, quotable as is.", + "type": "string" + }, + "max": { + "description": "The component's weight; the five maximums add to 100.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "points": { + "description": "Points earned, one decimal.", + "minimum": 0, + "type": "number" + }, + "source": { + "enum": [ + "snotel", + "model", + "operator", + "profile", + "derived", + "none" + ], + "type": "string" + } + }, + "required": [ + "points", + "max", + "basis", + "source" + ], + "type": "object" + }, + "snowQuality": { + "additionalProperties": false, + "description": "15: days since the last snow day × the 3-day high temperature × the engine's surface tags.", + "properties": { + "basis": { + "description": "One line saying what the points rest on, quotable as is.", + "type": "string" + }, + "max": { + "description": "The component's weight; the five maximums add to 100.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "points": { + "description": "Points earned, one decimal.", + "minimum": 0, + "type": "number" + }, + "source": { + "enum": [ + "snotel", + "model", + "operator", + "profile", + "derived", + "none" + ], + "type": "string" + } + }, + "required": [ + "points", + "max", + "basis", + "source" + ], + "type": "object" + } + }, + "required": [ + "depthVsNormal", + "recentSnow7d", + "forecast7d", + "snowQuality", + "operatingStatus" + ], + "type": "object" + }, + "date": { + "description": "YYYY-MM-DD the score is for (Mountain-time day of the scoring run).", + "type": "string" + }, + "rating": { + "description": "The score's four-tier label: great ≥ 75, good ≥ 55, fair ≥ 35, else poor.", + "enum": [ + "great", + "good", + "fair", + "poor" + ], + "type": "string" + }, + "score": { + "maximum": 100, + "minimum": 0, + "type": "integer" + }, + "scoredBy": { + "const": "algorithmic", + "description": "Always `algorithmic`: a fixed function of measured and modelled inputs, never an editorial call.", + "type": "string" + }, + "tagline": { + "description": "Dated sentence to quote: the score, its rating and the components strongest first.", + "type": "string" + }, + "version": { + "description": "Formula version, e.g. `score-v1`; a change re-scores the history.", + "type": "string" + } + }, + "required": [ + "date", + "score", + "rating", + "tagline", + "components", + "scoredBy", + "version" + ], + "type": "object" + }, + { + "type": "null" + } +] - changed
Output schema / properties / score / descriptionPrevious value: -"Today's 0–100 score, once the scorer is live."New value: +"Today's 0–100 Snow Score with components (P7). Null when the scorer has not written a row at most 3 days old; absent only when the score table is not served."
- Added
get_score - Changed
search_resorts1 field changed- added
Output schema / properties / resorts / items / properties / scoreAdded value: +{ + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "date": { + "description": "YYYY-MM-DD.", + "type": "string" + }, + "rating": { + "enum": [ + "great", + "good", + "fair", + "poor" + ], + "type": "string" + }, + "score": { + "maximum": 100, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "date", + "score", + "rating" + ], + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Today's Snow Score (P7); null before the first scoring run, absent when the table is not served. Components at `/resorts/{slug}/score-components`." +}
1 tool update
- Changed
get_resort_conditions6 fields changed- added
Output schema / properties / dataAdded value: +{ + "additionalProperties": false, + "properties": { + "baseDepthIn": { + "additionalProperties": false, + "description": "Measured (or model) base depth from the snow report, inches. Prefer this over `operatorBaseDepthIn`.", + "properties": { + "confidence": { + "description": "0–1: SNOTEL 0.9, other stations 0.8, operator 0.7, profile 0.6, derived 0.6, model 0.5; halved when stale, 0 when unknown.", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "freshness": { + "additionalProperties": false, + "properties": { + "ageHours": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Hours between the observation and `generatedAt`, one decimal; null for static facts and empty fields." + }, + "tier": { + "enum": [ + "live", + "recent", + "estimated", + "stale", + "unknown" + ], + "type": "string" + } + }, + "required": [ + "tier", + "ageHours" + ], + "type": "object" + }, + "observedAt": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "ISO-8601 instant the value was observed or published; null for static facts and empty fields." + }, + "source": { + "enum": [ + "snotel", + "station:snotel", + "station:ghcn", + "station:nws", + "station:bc_asws", + "station:eccc", + "operator", + "model", + "profile", + "derived", + "none" + ], + "type": "string" + }, + "value": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Null when PeakCam has nothing for this field." + } + }, + "required": [ + "value", + "source", + "observedAt", + "confidence", + "freshness" + ], + "type": "object" + }, + "depthDisagreement": { + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "differencePct": { + "description": "|measured − operator| as a percent of the larger value; present only above 30 %.", + "type": "number" + }, + "measuredIn": { + "type": "number" + }, + "note": { + "type": "string" + }, + "operatorIn": { + "type": "number" + }, + "preferred": { + "const": "measured", + "type": "string" + } + }, + "required": [ + "measuredIn", + "operatorIn", + "differencePct", + "preferred", + "note" + ], + "type": "object" + }, + { + "type": "null" + } + ] + }, + "forecastNext48hCm": { + "additionalProperties": false, + "description": "Blended forecast snowfall over the next 48 h, cm (P4 blend, summit point).", + "properties": { + "confidence": { + "description": "0–1: SNOTEL 0.9, other stations 0.8, operator 0.7, profile 0.6, derived 0.6, model 0.5; halved when stale, 0 when unknown.", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "freshness": { + "additionalProperties": false, + "properties": { + "ageHours": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Hours between the observation and `generatedAt`, one decimal; null for static facts and empty fields." + }, + "tier": { + "enum": [ + "live", + "recent", + "estimated", + "stale", + "unknown" + ], + "type": "string" + } + }, + "required": [ + "tier", + "ageHours" + ], + "type": "object" + }, + "observedAt": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "ISO-8601 instant the value was observed or published; null for static facts and empty fields." + }, + "source": { + "enum": [ + "snotel", + "station:snotel", + "station:ghcn", + "station:nws", + "station:bc_asws", + "station:eccc", + "operator", + "model", + "profile", + "derived", + "none" + ], + "type": "string" + }, + "value": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Null when PeakCam has nothing for this field." + } + }, + "required": [ + "value", + "source", + "observedAt", + "confidence", + "freshness" + ], + "type": "object" + }, + "liftsOpen": { + "additionalProperties": false, + "description": "Lifts open per the operator feed.", + "properties": { + "confidence": { + "description": "0–1: SNOTEL 0.9, other stations 0.8, operator 0.7, profile 0.6, derived 0.6, model 0.5; halved when stale, 0 when unknown.", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "freshness": { + "additionalProperties": false, + "properties": { + "ageHours": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Hours between the observation and `generatedAt`, one decimal; null for static facts and empty fields." + }, + "tier": { + "enum": [ + "live", + "recent", + "estimated", + "stale", + "unknown" + ], + "type": "string" + } + }, + "required": [ + "tier", + "ageHours" + ], + "type": "object" + }, + "observedAt": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "ISO-8601 instant the value was observed or published; null for static facts and empty fields." + }, + "source": { + "enum": [ + "snotel", + "station:snotel", + "station:ghcn", + "station:nws", + "station:bc_asws", + "station:eccc", + "operator", + "model", + "profile", + "derived", + "none" + ], + "type": "string" + }, + "value": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Null when PeakCam has nothing for this field." + } + }, + "required": [ + "value", + "source", + "observedAt", + "confidence", + "freshness" + ], + "type": "object" + }, + "liftsTotal": { + "additionalProperties": false, + "description": "From the operator feed when it lists lifts, else the profile total.", + "properties": { + "confidence": { + "description": "0–1: SNOTEL 0.9, other stations 0.8, operator 0.7, profile 0.6, derived 0.6, model 0.5; halved when stale, 0 when unknown.", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "freshness": { + "additionalProperties": false, + "properties": { + "ageHours": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Hours between the observation and `generatedAt`, one decimal; null for static facts and empty fields." + }, + "tier": { + "enum": [ + "live", + "recent", + "estimated", + "stale", + "unknown" + ], + "type": "string" + } + }, + "required": [ + "tier", + "ageHours" + ], + "type": "object" + }, + "observedAt": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "ISO-8601 instant the value was observed or published; null for static facts and empty fields." + }, + "source": { + "enum": [ + "snotel", + "station:snotel", + "station:ghcn", + "station:nws", + "station:bc_asws", + "station:eccc", + "operator", + "model", + "profile", + "derived", + "none" + ], + "type": "string" + }, + "value": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Null when PeakCam has nothing for this field." + } + }, + "required": [ + "value", + "source", + "observedAt", + "confidence", + "freshness" + ], + "type": "object" + }, + "newSnow24hIn": { + "additionalProperties": false, + "properties": { + "confidence": { + "description": "0–1: SNOTEL 0.9, other stations 0.8, operator 0.7, profile 0.6, derived 0.6, model 0.5; halved when stale, 0 when unknown.", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "freshness": { + "additionalProperties": false, + "properties": { + "ageHours": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Hours between the observation and `generatedAt`, one decimal; null for static facts and empty fields." + }, + "tier": { + "enum": [ + "live", + "recent", + "estimated", + "stale", + "unknown" + ], + "type": "string" + } + }, + "required": [ + "tier", + "ageHours" + ], + "type": "object" + }, + "observedAt": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "ISO-8601 instant the value was observed or published; null for static facts and empty fields." + }, + "source": { + "enum": [ + "snotel", + "station:snotel", + "station:ghcn", + "station:nws", + "station:bc_asws", + "station:eccc", + "operator", + "model", + "profile", + "derived", + "none" + ], + "type": "string" + }, + "value": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Null when PeakCam has nothing for this field." + } + }, + "required": [ + "value", + "source", + "observedAt", + "confidence", + "freshness" + ], + "type": "object" + }, + "newSnow48hIn": { + "additionalProperties": false, + "properties": { + "confidence": { + "description": "0–1: SNOTEL 0.9, other stations 0.8, operator 0.7, profile 0.6, derived 0.6, model 0.5; halved when stale, 0 when unknown.", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "freshness": { + "additionalProperties": false, + "properties": { + "ageHours": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Hours between the observation and `generatedAt`, one decimal; null for static facts and empty fields." + }, + "tier": { + "enum": [ + "live", + "recent", + "estimated", + "stale", + "unknown" + ], + "type": "string" + } + }, + "required": [ + "tier", + "ageHours" + ], + "type": "object" + }, + "observedAt": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "ISO-8601 instant the value was observed or published; null for static facts and empty fields." + }, + "source": { + "enum": [ + "snotel", + "station:snotel", + "station:ghcn", + "station:nws", + "station:bc_asws", + "station:eccc", + "operator", + "model", + "profile", + "derived", + "none" + ], + "type": "string" + }, + "value": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Null when PeakCam has nothing for this field." + } + }, + "required": [ + "value", + "source", + "observedAt", + "confidence", + "freshness" + ], + "type": "object" + }, + "operatorBaseDepthIn": { + "additionalProperties": false, + "description": "The operator's own base figure, when a feed carries one.", + "properties": { + "confidence": { + "description": "0–1: SNOTEL 0.9, other stations 0.8, operator 0.7, profile 0.6, derived 0.6, model 0.5; halved when stale, 0 when unknown.", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "freshness": { + "additionalProperties": false, + "properties": { + "ageHours": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Hours between the observation and `generatedAt`, one decimal; null for static facts and empty fields." + }, + "tier": { + "enum": [ + "live", + "recent", + "estimated", + "stale", + "unknown" + ], + "type": "string" + } + }, + "required": [ + "tier", + "ageHours" + ], + "type": "object" + }, + "observedAt": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "ISO-8601 instant the value was observed or published; null for static facts and empty fields." + }, + "source": { + "enum": [ + "snotel", + "station:snotel", + "station:ghcn", + "station:nws", + "station:bc_asws", + "station:eccc", + "operator", + "model", + "profile", + "derived", + "none" + ], + "type": "string" + }, + "value": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Null when PeakCam has nothing for this field." + } + }, + "required": [ + "value", + "source", + "observedAt", + "confidence", + "freshness" + ], + "type": "object" + }, + "percentOfNormal": { + "additionalProperties": false, + "description": "SWE against the station's 1991–2020 median, inside the publishable band.", + "properties": { + "confidence": { + "description": "0–1: SNOTEL 0.9, other stations 0.8, operator 0.7, profile 0.6, derived 0.6, model 0.5; halved when stale, 0 when unknown.", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "freshness": { + "additionalProperties": false, + "properties": { + "ageHours": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Hours between the observation and `generatedAt`, one decimal; null for static facts and empty fields." + }, + "tier": { + "enum": [ + "live", + "recent", + "estimated", + "stale", + "unknown" + ], + "type": "string" + } + }, + "required": [ + "tier", + "ageHours" + ], + "type": "object" + }, + "observedAt": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "ISO-8601 instant the value was observed or published; null for static facts and empty fields." + }, + "source": { + "enum": [ + "snotel", + "station:snotel", + "station:ghcn", + "station:nws", + "station:bc_asws", + "station:eccc", + "operator", + "model", + "profile", + "derived", + "none" + ], + "type": "string" + }, + "value": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Null when PeakCam has nothing for this field." + } + }, + "required": [ + "value", + "source", + "observedAt", + "confidence", + "freshness" + ], + "type": "object" + }, + "reasons": { + "description": "Why the status and the verdict came out as they did, in order; quote them.", + "items": { + "type": "string" + }, + "type": "array" + }, + "recommendableToday": { + "description": "True only when the status is OPEN on a usable source, a current base depth is on file and the rating is not poor.", + "type": "boolean" + }, + "runsOpen": { + "additionalProperties": false, + "properties": { + "confidence": { + "description": "0–1: SNOTEL 0.9, other stations 0.8, operator 0.7, profile 0.6, derived 0.6, model 0.5; halved when stale, 0 when unknown.", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "freshness": { + "additionalProperties": false, + "properties": { + "ageHours": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Hours between the observation and `generatedAt`, one decimal; null for static facts and empty fields." + }, + "tier": { + "enum": [ + "live", + "recent", + "estimated", + "stale", + "unknown" + ], + "type": "string" + } + }, + "required": [ + "tier", + "ageHours" + ], + "type": "object" + }, + "observedAt": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "ISO-8601 instant the value was observed or published; null for static facts and empty fields." + }, + "source": { + "enum": [ + "snotel", + "station:snotel", + "station:ghcn", + "station:nws", + "station:bc_asws", + "station:eccc", + "operator", + "model", + "profile", + "derived", + "none" + ], + "type": "string" + }, + "value": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Null when PeakCam has nothing for this field." + } + }, + "required": [ + "value", + "source", + "observedAt", + "confidence", + "freshness" + ], + "type": "object" + }, + "runsTotal": { + "additionalProperties": false, + "properties": { + "confidence": { + "description": "0–1: SNOTEL 0.9, other stations 0.8, operator 0.7, profile 0.6, derived 0.6, model 0.5; halved when stale, 0 when unknown.", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "freshness": { + "additionalProperties": false, + "properties": { + "ageHours": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Hours between the observation and `generatedAt`, one decimal; null for static facts and empty fields." + }, + "tier": { + "enum": [ + "live", + "recent", + "estimated", + "stale", + "unknown" + ], + "type": "string" + } + }, + "required": [ + "tier", + "ageHours" + ], + "type": "object" + }, + "observedAt": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "ISO-8601 instant the value was observed or published; null for static facts and empty fields." + }, + "source": { + "enum": [ + "snotel", + "station:snotel", + "station:ghcn", + "station:nws", + "station:bc_asws", + "station:eccc", + "operator", + "model", + "profile", + "derived", + "none" + ], + "type": "string" + }, + "value": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Null when PeakCam has nothing for this field." + } + }, + "required": [ + "value", + "source", + "observedAt", + "confidence", + "freshness" + ], + "type": "object" + }, + "seasonClosing": { + "additionalProperties": false, + "description": "YYYY-MM-DD, mainly Southern-hemisphere rows.", + "properties": { + "confidence": { + "description": "0–1: SNOTEL 0.9, other stations 0.8, operator 0.7, profile 0.6, derived 0.6, model 0.5; halved when stale, 0 when unknown.", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "freshness": { + "additionalProperties": false, + "properties": { + "ageHours": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Hours between the observation and `generatedAt`, one decimal; null for static facts and empty fields." + }, + "tier": { + "enum": [ + "live", + "recent", + "estimated", + "stale", + "unknown" + ], + "type": "string" + } + }, + "required": [ + "tier", + "ageHours" + ], + "type": "object" + }, + "observedAt": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "ISO-8601 instant the value was observed or published; null for static facts and empty fields." + }, + "source": { + "enum": [ + "snotel", + "station:snotel", + "station:ghcn", + "station:nws", + "station:bc_asws", + "station:eccc", + "operator", + "model", + "profile", + "derived", + "none" + ], + "type": "string" + }, + "value": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Null when PeakCam has nothing for this field." + } + }, + "required": [ + "value", + "source", + "observedAt", + "confidence", + "freshness" + ], + "type": "object" + }, + "seasonOpening": { + "additionalProperties": false, + "description": "YYYY-MM-DD. Source `operator` for a resort-confirmed date, `profile` for a third-party projection.", + "properties": { + "confidence": { + "description": "0–1: SNOTEL 0.9, other stations 0.8, operator 0.7, profile 0.6, derived 0.6, model 0.5; halved when stale, 0 when unknown.", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "freshness": { + "additionalProperties": false, + "properties": { + "ageHours": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Hours between the observation and `generatedAt`, one decimal; null for static facts and empty fields." + }, + "tier": { + "enum": [ + "live", + "recent", + "estimated", + "stale", + "unknown" + ], + "type": "string" + } + }, + "required": [ + "tier", + "ageHours" + ], + "type": "object" + }, + "observedAt": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "ISO-8601 instant the value was observed or published; null for static facts and empty fields." + }, + "source": { + "enum": [ + "snotel", + "station:snotel", + "station:ghcn", + "station:nws", + "station:bc_asws", + "station:eccc", + "operator", + "model", + "profile", + "derived", + "none" + ], + "type": "string" + }, + "value": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Null when PeakCam has nothing for this field." + } + }, + "required": [ + "value", + "source", + "observedAt", + "confidence", + "freshness" + ], + "type": "object" + }, + "snowQuality": { + "additionalProperties": false, + "properties": { + "confidence": { + "description": "0–1: SNOTEL 0.9, other stations 0.8, operator 0.7, profile 0.6, derived 0.6, model 0.5; halved when stale, 0 when unknown.", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "freshness": { + "additionalProperties": false, + "properties": { + "ageHours": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Hours between the observation and `generatedAt`, one decimal; null for static facts and empty fields." + }, + "tier": { + "enum": [ + "live", + "recent", + "estimated", + "stale", + "unknown" + ], + "type": "string" + } + }, + "required": [ + "tier", + "ageHours" + ], + "type": "object" + }, + "observedAt": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "ISO-8601 instant the value was observed or published; null for static facts and empty fields." + }, + "source": { + "enum": [ + "snotel", + "station:snotel", + "station:ghcn", + "station:nws", + "station:bc_asws", + "station:eccc", + "operator", + "model", + "profile", + "derived", + "none" + ], + "type": "string" + }, + "value": { + "anyOf": [ + { + "enum": [ + "powder", + "packed", + "spring", + "ice" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Null when PeakCam has nothing for this field." + } + }, + "required": [ + "value", + "source", + "observedAt", + "confidence", + "freshness" + ], + "type": "object" + }, + "status": { + "additionalProperties": false, + "properties": { + "confidence": { + "description": "0–1: SNOTEL 0.9, other stations 0.8, operator 0.7, profile 0.6, derived 0.6, model 0.5; halved when stale, 0 when unknown.", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "freshness": { + "additionalProperties": false, + "properties": { + "ageHours": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Hours between the observation and `generatedAt`, one decimal; null for static facts and empty fields." + }, + "tier": { + "enum": [ + "live", + "recent", + "estimated", + "stale", + "unknown" + ], + "type": "string" + } + }, + "required": [ + "tier", + "ageHours" + ], + "type": "object" + }, + "observedAt": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "ISO-8601 instant the value was observed or published; null for static facts and empty fields." + }, + "source": { + "enum": [ + "snotel", + "station:snotel", + "station:ghcn", + "station:nws", + "station:bc_asws", + "station:eccc", + "operator", + "model", + "profile", + "derived", + "none" + ], + "type": "string" + }, + "value": { + "anyOf": [ + { + "enum": [ + "OPEN", + "CLOSED_TODAY", + "PRE_SEASON", + "OFF_SEASON", + "UNKNOWN" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Null when PeakCam has nothing for this field." + } + }, + "required": [ + "value", + "source", + "observedAt", + "confidence", + "freshness" + ], + "type": "object" + }, + "surface": { + "additionalProperties": false, + "description": "Operator-reported surface, when a feed carries one.", + "properties": { + "confidence": { + "description": "0–1: SNOTEL 0.9, other stations 0.8, operator 0.7, profile 0.6, derived 0.6, model 0.5; halved when stale, 0 when unknown.", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "freshness": { + "additionalProperties": false, + "properties": { + "ageHours": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Hours between the observation and `generatedAt`, one decimal; null for static facts and empty fields." + }, + "tier": { + "enum": [ + "live", + "recent", + "estimated", + "stale", + "unknown" + ], + "type": "string" + } + }, + "required": [ + "tier", + "ageHours" + ], + "type": "object" + }, + "observedAt": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "ISO-8601 instant the value was observed or published; null for static facts and empty fields." + }, + "source": { + "enum": [ + "snotel", + "station:snotel", + "station:ghcn", + "station:nws", + "station:bc_asws", + "station:eccc", + "operator", + "model", + "profile", + "derived", + "none" + ], + "type": "string" + }, + "value": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Null when PeakCam has nothing for this field." + } + }, + "required": [ + "value", + "source", + "observedAt", + "confidence", + "freshness" + ], + "type": "object" + }, + "sweIn": { + "additionalProperties": false, + "description": "Snow water equivalent, inches.", + "properties": { + "confidence": { + "description": "0–1: SNOTEL 0.9, other stations 0.8, operator 0.7, profile 0.6, derived 0.6, model 0.5; halved when stale, 0 when unknown.", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "freshness": { + "additionalProperties": false, + "properties": { + "ageHours": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Hours between the observation and `generatedAt`, one decimal; null for static facts and empty fields." + }, + "tier": { + "enum": [ + "live", + "recent", + "estimated", + "stale", + "unknown" + ], + "type": "string" + } + }, + "required": [ + "tier", + "ageHours" + ], + "type": "object" + }, + "observedAt": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "ISO-8601 instant the value was observed or published; null for static facts and empty fields." + }, + "source": { + "enum": [ + "snotel", + "station:snotel", + "station:ghcn", + "station:nws", + "station:bc_asws", + "station:eccc", + "operator", + "model", + "profile", + "derived", + "none" + ], + "type": "string" + }, + "value": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Null when PeakCam has nothing for this field." + } + }, + "required": [ + "value", + "source", + "observedAt", + "confidence", + "freshness" + ], + "type": "object" + }, + "tempF": { + "additionalProperties": false, + "description": "The highest station with a temperature (summit first).", + "properties": { + "confidence": { + "description": "0–1: SNOTEL 0.9, other stations 0.8, operator 0.7, profile 0.6, derived 0.6, model 0.5; halved when stale, 0 when unknown.", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "freshness": { + "additionalProperties": false, + "properties": { + "ageHours": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Hours between the observation and `generatedAt`, one decimal; null for static facts and empty fields." + }, + "tier": { + "enum": [ + "live", + "recent", + "estimated", + "stale", + "unknown" + ], + "type": "string" + } + }, + "required": [ + "tier", + "ageHours" + ], + "type": "object" + }, + "observedAt": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "ISO-8601 instant the value was observed or published; null for static facts and empty fields." + }, + "source": { + "enum": [ + "snotel", + "station:snotel", + "station:ghcn", + "station:nws", + "station:bc_asws", + "station:eccc", + "operator", + "model", + "profile", + "derived", + "none" + ], + "type": "string" + }, + "value": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Null when PeakCam has nothing for this field." + } + }, + "required": [ + "value", + "source", + "observedAt", + "confidence", + "freshness" + ], + "type": "object" + }, + "windMph": { + "additionalProperties": false, + "properties": { + "confidence": { + "description": "0–1: SNOTEL 0.9, other stations 0.8, operator 0.7, profile 0.6, derived 0.6, model 0.5; halved when stale, 0 when unknown.", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "freshness": { + "additionalProperties": false, + "properties": { + "ageHours": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Hours between the observation and `generatedAt`, one decimal; null for static facts and empty fields." + }, + "tier": { + "enum": [ + "live", + "recent", + "estimated", + "stale", + "unknown" + ], + "type": "string" + } + }, + "required": [ + "tier", + "ageHours" + ], + "type": "object" + }, + "observedAt": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "ISO-8601 instant the value was observed or published; null for static facts and empty fields." + }, + "source": { + "enum": [ + "snotel", + "station:snotel", + "station:ghcn", + "station:nws", + "station:bc_asws", + "station:eccc", + "operator", + "model", + "profile", + "derived", + "none" + ], + "type": "string" + }, + "value": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Null when PeakCam has nothing for this field." + } + }, + "required": [ + "value", + "source", + "observedAt", + "confidence", + "freshness" + ], + "type": "object" + } + }, + "required": [ + "status", + "recommendableToday", + "reasons", + "depthDisagreement", + "seasonOpening", + "seasonClosing", + "baseDepthIn", + "operatorBaseDepthIn", + "newSnow24hIn", + "newSnow48hIn", + "sweIn", + "liftsOpen", + "liftsTotal", + "runsOpen", + "runsTotal", + "surface", + "snowQuality", + "tempF", + "windMph", + "forecastNext48hCm", + "percentOfNormal" + ], + "type": "object" +} - added
Output schema / properties / metaAdded value: +{ + "additionalProperties": false, + "properties": { + "freshness": { + "additionalProperties": { + "enum": [ + "live", + "recent", + "estimated", + "stale", + "unknown" + ], + "type": "string" + }, + "description": "Freshness tier per field.", + "propertyNames": { + "enum": [ + "status", + "seasonOpening", + "seasonClosing", + "baseDepthIn", + "operatorBaseDepthIn", + "newSnow24hIn", + "newSnow48hIn", + "sweIn", + "liftsOpen", + "liftsTotal", + "runsOpen", + "runsTotal", + "surface", + "snowQuality", + "tempF", + "windMph", + "forecastNext48hCm", + "percentOfNormal" + ], + "type": "string" + }, + "required": [ + "status", + "seasonOpening", + "seasonClosing", + "baseDepthIn", + "operatorBaseDepthIn", + "newSnow24hIn", + "newSnow48hIn", + "sweIn", + "liftsOpen", + "liftsTotal", + "runsOpen", + "runsTotal", + "surface", + "snowQuality", + "tempF", + "windMph", + "forecastNext48hCm", + "percentOfNormal" + ], + "type": "object" + }, + "generatedAt": { + "type": "string" + }, + "localDate": { + "description": "YYYY-MM-DD at the resort when the status was resolved.", + "type": "string" + }, + "newestObservationAt": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "The newest `observedAt` across the populated fields." + }, + "resolvedAt": { + "description": "ISO instant the status was evaluated at (ages are measured from it).", + "type": "string" + }, + "sources": { + "description": "Distinct sources used, best first.", + "items": { + "enum": [ + "snotel", + "station:snotel", + "station:ghcn", + "station:nws", + "station:bc_asws", + "station:eccc", + "operator", + "model", + "profile", + "derived", + "none" + ], + "type": "string" + }, + "type": "array" + }, + "timeZone": { + "description": "IANA zone the resort's calendar day runs on.", + "type": "string" + } + }, + "required": [ + "generatedAt", + "resolvedAt", + "timeZone", + "localDate", + "newestObservationAt", + "freshness", + "sources" + ], + "type": "object" +} - added
Output schema / properties / schemaUrlAdded value: +{ + "description": "The JSON Schema this document validates against.", + "type": "string" +} - added
Output schema / properties / schemaVersionAdded value: +{ + "const": "1.0.0", + "description": "Contract version; the schema file name carries the major.", + "type": "string" +} - added
Output schema / properties / sentenceAdded value: +{ + "description": "A dated, source-labelled status sentence that can be quoted verbatim.", + "type": "string" +} - changed
Output schema / requiredPrevious value: -[ - "slug", - "name", - "canonicalUrl", - "apiUrl", - "location", - "profile", - "snow", - "season", - "cams", - "websiteUrl", - "attribution", - "license", - "updatedAt" -]New value: +[ + "slug", + "name", + "canonicalUrl", + "apiUrl", + "location", + "profile", + "snow", + "season", + "cams", + "websiteUrl", + "attribution", + "license", + "updatedAt", + "schemaVersion", + "schemaUrl", + "sentence", + "meta", + "data" +]
3 tool updates
- Changed
get_resort_cams8 fields changed- added
Output schema / properties / cams / items / properties / timelapses / items / properties / bytesAdded value: +{ + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Size of the MP4." +} - added
Output schema / properties / cams / items / properties / timelapses / items / properties / endsAtAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Capture time of the last frame (ISO-8601)." +} - added
Output schema / properties / cams / items / properties / timelapses / items / properties / frames / descriptionAdded value: +"Archived frames in the clip; at 7 fps the duration is frames / 7 seconds." - added
Output schema / properties / cams / items / properties / timelapses / items / properties / posterUrlAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Public JPEG of the clip's last frame, the <video> poster. Null for clips rendered before the poster existed." +} - added
Output schema / properties / cams / items / properties / timelapses / items / properties / startsAtAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Capture time of the first frame (ISO-8601)." +} - changed
Output schema / properties / cams / items / properties / timelapses / items / properties / url / descriptionPrevious value: -"Public MP4 URL."New value: +"Public MP4 URL (H.264, 7 fps, 720p max, at most 3 MB). Link it; never inline it." - changed
Output schema / properties / cams / items / properties / timelapses / items / properties / window / descriptionPrevious value: -"Which clip: `24h` (rolling day), `storm` (one storm, see `stormDate`), or another label."New value: +"Which clip: `24h` (rolling day, replaced every render), `storm` (one storm, see `stormDate`), or another label." - changed
Output schema / properties / cams / items / properties / timelapses / items / requiredPrevious value: -[ - "id", - "window", - "url", - "frames", - "renderedAt", - "stormDate" -]New value: +[ + "id", + "window", + "url", + "posterUrl", + "frames", + "startsAt", + "endsAt", + "bytes", + "renderedAt", + "stormDate" +]
- Changed
get_resort_conditions8 fields changed- added
Output schema / properties / cams / items / properties / timelapses / items / properties / bytesAdded value: +{ + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Size of the MP4." +} - added
Output schema / properties / cams / items / properties / timelapses / items / properties / endsAtAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Capture time of the last frame (ISO-8601)." +} - added
Output schema / properties / cams / items / properties / timelapses / items / properties / frames / descriptionAdded value: +"Archived frames in the clip; at 7 fps the duration is frames / 7 seconds." - added
Output schema / properties / cams / items / properties / timelapses / items / properties / posterUrlAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Public JPEG of the clip's last frame, the <video> poster. Null for clips rendered before the poster existed." +} - added
Output schema / properties / cams / items / properties / timelapses / items / properties / startsAtAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Capture time of the first frame (ISO-8601)." +} - changed
Output schema / properties / cams / items / properties / timelapses / items / properties / url / descriptionPrevious value: -"Public MP4 URL."New value: +"Public MP4 URL (H.264, 7 fps, 720p max, at most 3 MB). Link it; never inline it." - changed
Output schema / properties / cams / items / properties / timelapses / items / properties / window / descriptionPrevious value: -"Which clip: `24h` (rolling day), `storm` (one storm, see `stormDate`), or another label."New value: +"Which clip: `24h` (rolling day, replaced every render), `storm` (one storm, see `stormDate`), or another label." - changed
Output schema / properties / cams / items / properties / timelapses / items / requiredPrevious value: -[ - "id", - "window", - "url", - "frames", - "renderedAt", - "stormDate" -]New value: +[ + "id", + "window", + "url", + "posterUrl", + "frames", + "startsAt", + "endsAt", + "bytes", + "renderedAt", + "stormDate" +]
- Added
get_timelapses
8 tool updates
- Added
compare_models - Changed
compare_resorts7 fields changed- added
Output schema / properties / resorts / items / properties / forecast / anyOfAdded value: +[ + { + "additionalProperties": false, + "properties": { + "issuedAt": { + "description": "Newest model issue instant among the runs blended.", + "type": "string" + }, + "modelCount": { + "description": "Models contributing to the first day.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "models": { + "description": "Every model id that contributed to any day.", + "items": { + "type": "string" + }, + "type": "array" + }, + "next48hCm": { + "type": "number" + }, + "next48hIn": { + "type": "number" + }, + "peak": { + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "cm": { + "type": "number" + }, + "date": { + "description": "The day with the most blended snowfall.", + "type": "string" + }, + "in": { + "type": "number" + }, + "windowDays": { + "description": "Consecutive days around the peak with at least 1 cm (the storm window).", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "required": [ + "date", + "in", + "cm", + "windowDays" + ], + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Null when no day has any blended snow." + }, + "point": { + "description": "The elevation the summary is for: summit when the resort has a summit point, else base.", + "enum": [ + "summit", + "base" + ], + "type": "string" + }, + "total14dCm": { + "type": "number" + }, + "total14dIn": { + "type": "number" + }, + "total7dCm": { + "type": "number" + }, + "total7dIn": { + "type": "number" + } + }, + "required": [ + "point", + "issuedAt", + "modelCount", + "models", + "next48hIn", + "next48hCm", + "total7dIn", + "total7dCm", + "total14dIn", + "total14dCm", + "peak" + ], + "type": "object" + }, + { + "type": "null" + } +] - changed
Output schema / properties / resorts / items / properties / forecast / descriptionPrevious value: -"Latest run per model and point, once stored forecasts are live."New value: +"Headline numbers from the blended 14-day forecast (summit point when one exists). Null when no run is current; absent on list and compare rows. The full daily blend and every model run are at `/resorts/{slug}/forecast`." - removed
Output schema / properties / resorts / items / properties / forecast / itemsRemoved value: -{ - "additionalProperties": false, - "properties": { - "days": { - "items": { - "additionalProperties": false, - "properties": { - "date": { - "description": "YYYY-MM-DD, local to the resort.", - "type": "string" - }, - "precipProb": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "0–100." - }, - "snowfallCm": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ] - }, - "snowfallHi": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ] - }, - "snowfallLo": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Low end of the spread across models / members; null for a single model." - }, - "tempMax": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "°C as the models report it." - }, - "tempMin": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ] - }, - "weatherCode": { - "anyOf": [ - { - "maximum": 9007199254740991, - "minimum": -9007199254740991, - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "WMO weather interpretation code." - }, - "windGust": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "km/h." - } - }, - "required": [ - "date", - "snowfallCm", - "snowfallLo", - "snowfallHi", - "tempMax", - "tempMin", - "precipProb", - "windGust", - "weatherCode" - ], - "type": "object" - }, - "type": "array" - }, - "horizonDays": { - "maximum": 9007199254740991, - "minimum": -9007199254740991, - "type": "integer" - }, - "id": { - "type": "string" - }, - "issuedAt": { - "type": "string" - }, - "model": { - "description": "Model id as the provider names it, or `blend` for PeakCam's skill-weighted blend.", - "type": "string" - }, - "point": { - "enum": [ - "summit", - "base" - ], - "type": "string" - } - }, - "required": [ - "id", - "point", - "model", - "issuedAt", - "horizonDays", - "days" - ], - "type": "object" -} - removed
Output schema / properties / resorts / items / properties / forecast / typeRemoved value: -"array" - changed
Output schema / properties / resorts / items / properties / forecastScores / descriptionPrevious value: -"Per-model verification at this resort, once computed."New value: +"Per-model verification at this resort over 90 days, ranked; empty until the scorer has measured days. Detail at `/resorts/{slug}/forecast-accuracy`." - added
Output schema / properties / resorts / items / properties / forecastScores / items / properties / rankAdded value: +{ + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "1 = lowest day-1 MAE among the models scored at this resort (the blend is ranked too). Null before the first scoring run." +} - changed
Output schema / properties / resorts / items / properties / forecastScores / items / requiredPrevious value: -[ - "model", - "periodDays", - "day1Mae", - "day3Mae", - "day7Mae", - "samples", - "biasRatio", - "computedAt" -]New value: +[ + "model", + "periodDays", + "day1Mae", + "day3Mae", + "day7Mae", + "samples", + "biasRatio", + "computedAt", + "rank" +]
- Changed
get_forecast24 fields changed- added
Input schema / properties / pointAdded value: +{ + "default": "summit", + "description": "Which elevation's blend. Falls back to the other point with a note when the asked one has no runs.", + "enum": [ + "summit", + "base" + ], + "type": "string" +} - added
Output schema / properties / creditsAdded value: +{ + "items": { + "additionalProperties": false, + "properties": { + "license": { + "description": "Licence of the source data, e.g. `CC BY 4.0`.", + "type": "string" + }, + "name": { + "type": "string" + }, + "text": { + "description": "The attribution line to carry with any reuse, e.g. `Weather data by Open-Meteo.com`.", + "type": "string" + }, + "url": { + "type": "string" + } + }, + "required": [ + "name", + "text", + "license", + "url" + ], + "type": "object" + }, + "type": "array" +} - added
Output schema / properties / daysAdded value: +{ + "description": "Up to 14 blended days.", + "items": { + "additionalProperties": false, + "properties": { + "condition": { + "description": "PeakCam icon slug for the weather code (`heavy-snow`, `clear`, ...).", + "type": "string" + }, + "date": { + "description": "YYYY-MM-DD, local to the resort.", + "type": "string" + }, + "modelCount": { + "description": "Models contributing to this day. Falls with lead time as shorter-range models drop out.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "models": { + "description": "Model ids contributing to this day.", + "items": { + "type": "string" + }, + "type": "array" + }, + "precipProb": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "0–100, median of the models that publish one." + }, + "snowfallCm": { + "type": "number" + }, + "snowfallHiCm": { + "type": "number" + }, + "snowfallHiIn": { + "description": "75th percentile across models, inches.", + "type": "number" + }, + "snowfallIn": { + "description": "Median across the models that reach this day, inches.", + "type": "number" + }, + "snowfallLoCm": { + "type": "number" + }, + "snowfallLoIn": { + "description": "25th percentile across models, inches. Equals the median when one model reaches the day.", + "type": "number" + }, + "tempMaxF": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "tempMinF": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "weatherCode": { + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Modal WMO code across models; ties go to the more severe code." + }, + "windGustMph": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "date", + "snowfallIn", + "snowfallLoIn", + "snowfallHiIn", + "snowfallCm", + "snowfallLoCm", + "snowfallHiCm", + "tempMaxF", + "tempMinF", + "precipProb", + "windGustMph", + "weatherCode", + "condition", + "modelCount", + "models" + ], + "type": "object" + }, + "type": "array" +} - added
Output schema / properties / forecastUrlAdded value: +{ + "description": "The REST document with every model run.", + "type": "string" +} - added
Output schema / properties / issuedAtAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Newest model issue instant among the runs blended." +} - added
Output schema / properties / modelCountAdded value: +{ + "description": "Models contributing to the first day.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" +} - added
Output schema / properties / modelsAdded value: +{ + "items": { + "type": "string" + }, + "type": "array" +} - added
Output schema / properties / periods / descriptionAdded value: +"NWS daily narrative for US resorts (up to 5 days); empty elsewhere or when NWS does not answer." - removed
Output schema / properties / periods / items / properties / condition / descriptionRemoved value: -"PeakCam condition key derived from the text." - removed
Output schema / properties / periods / items / properties / date / descriptionRemoved value: -"YYYY-MM-DD when NWS supplies it." - removed
Output schema / properties / periods / items / properties / dow / descriptionRemoved value: -"`Today`, then three-letter weekday." - removed
Output schema / properties / periods / items / properties / feelsLikeF / descriptionRemoved value: -"Wind-chill adjusted high." - removed
Output schema / properties / periods / items / properties / precipProbability / descriptionRemoved value: -"Percent." - removed
Output schema / properties / periods / items / properties / shortForecast / descriptionRemoved value: -"NWS short forecast text, e.g. `Snow Likely`." - added
Output schema / properties / periods / items / properties / snowInchesAdded value: +{ + "description": "From the blend when one is stored for that date, else the keyword estimate (see snowSource).", + "type": "number" +} - removed
Output schema / properties / periods / items / properties / snowInchesEstimateRemoved value: -{ - "description": "Keyword heuristic from the forecast text (blizzard/heavy snow 8, snow 3, flurries 1, else 0). Not a quantitative forecast; say so when quoting it.", - "type": "number" -} - added
Output schema / properties / periods / items / properties / snowSourceAdded value: +{ + "enum": [ + "blend", + "nws_keyword", + "open_meteo" + ], + "type": "string" +} - changed
Output schema / properties / periods / items / requiredPrevious value: -[ - "dow", - "date", - "shortForecast", - "condition", - "highF", - "lowF", - "snowInchesEstimate", - "precipProbability", - "windMph", - "windDirection", - "feelsLikeF" -]New value: +[ + "dow", + "date", + "shortForecast", + "condition", + "highF", + "lowF", + "snowInches", + "snowSource", + "precipProbability", + "windMph", + "windDirection", + "feelsLikeF" +] - added
Output schema / properties / pointAdded value: +{ + "anyOf": [ + { + "enum": [ + "summit", + "base" + ], + "type": "string" + }, + { + "type": "null" + } + ] +} - removed
Output schema / properties / provider / constRemoved value: -"nws" - added
Output schema / properties / provider / descriptionAdded value: +"`blend`: stored multi-model blend; `nws`: NWS narrative only, snow amounts are keyword estimates; `none`: nothing available." - added
Output schema / properties / provider / enumAdded value: +[ + "blend", + "nws", + "none" +] - added
Output schema / properties / summaryAdded value: +{ + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "issuedAt": { + "description": "Newest model issue instant among the runs blended.", + "type": "string" + }, + "modelCount": { + "description": "Models contributing to the first day.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "models": { + "description": "Every model id that contributed to any day.", + "items": { + "type": "string" + }, + "type": "array" + }, + "next48hCm": { + "type": "number" + }, + "next48hIn": { + "type": "number" + }, + "peak": { + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "cm": { + "type": "number" + }, + "date": { + "description": "The day with the most blended snowfall.", + "type": "string" + }, + "in": { + "type": "number" + }, + "windowDays": { + "description": "Consecutive days around the peak with at least 1 cm (the storm window).", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "required": [ + "date", + "in", + "cm", + "windowDays" + ], + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Null when no day has any blended snow." + }, + "point": { + "description": "The elevation the summary is for: summit when the resort has a summit point, else base.", + "enum": [ + "summit", + "base" + ], + "type": "string" + }, + "total14dCm": { + "type": "number" + }, + "total14dIn": { + "type": "number" + }, + "total7dCm": { + "type": "number" + }, + "total7dIn": { + "type": "number" + } + }, + "required": [ + "point", + "issuedAt", + "modelCount", + "models", + "next48hIn", + "next48hCm", + "total7dIn", + "total7dCm", + "total14dIn", + "total14dCm", + "peak" + ], + "type": "object" + }, + { + "type": "null" + } + ] +} - changed
Output schema / requiredPrevious value: -[ - "slug", - "name", - "canonicalUrl", - "provider", - "available", - "note", - "periods", - "generatedAt" -]New value: +[ + "slug", + "name", + "canonicalUrl", + "forecastUrl", + "provider", + "available", + "note", + "point", + "issuedAt", + "modelCount", + "models", + "summary", + "days", + "periods", + "credits", + "generatedAt" +]
- Added
get_leaderboard - Added
get_monthly_climatology - Changed
get_resort_conditions7 fields changed- added
Output schema / properties / forecast / anyOfAdded value: +[ + { + "additionalProperties": false, + "properties": { + "issuedAt": { + "description": "Newest model issue instant among the runs blended.", + "type": "string" + }, + "modelCount": { + "description": "Models contributing to the first day.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "models": { + "description": "Every model id that contributed to any day.", + "items": { + "type": "string" + }, + "type": "array" + }, + "next48hCm": { + "type": "number" + }, + "next48hIn": { + "type": "number" + }, + "peak": { + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "cm": { + "type": "number" + }, + "date": { + "description": "The day with the most blended snowfall.", + "type": "string" + }, + "in": { + "type": "number" + }, + "windowDays": { + "description": "Consecutive days around the peak with at least 1 cm (the storm window).", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "required": [ + "date", + "in", + "cm", + "windowDays" + ], + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Null when no day has any blended snow." + }, + "point": { + "description": "The elevation the summary is for: summit when the resort has a summit point, else base.", + "enum": [ + "summit", + "base" + ], + "type": "string" + }, + "total14dCm": { + "type": "number" + }, + "total14dIn": { + "type": "number" + }, + "total7dCm": { + "type": "number" + }, + "total7dIn": { + "type": "number" + } + }, + "required": [ + "point", + "issuedAt", + "modelCount", + "models", + "next48hIn", + "next48hCm", + "total7dIn", + "total7dCm", + "total14dIn", + "total14dCm", + "peak" + ], + "type": "object" + }, + { + "type": "null" + } +] - changed
Output schema / properties / forecast / descriptionPrevious value: -"Latest run per model and point, once stored forecasts are live."New value: +"Headline numbers from the blended 14-day forecast (summit point when one exists). Null when no run is current; absent on list and compare rows. The full daily blend and every model run are at `/resorts/{slug}/forecast`." - removed
Output schema / properties / forecast / itemsRemoved value: -{ - "additionalProperties": false, - "properties": { - "days": { - "items": { - "additionalProperties": false, - "properties": { - "date": { - "description": "YYYY-MM-DD, local to the resort.", - "type": "string" - }, - "precipProb": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "0–100." - }, - "snowfallCm": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ] - }, - "snowfallHi": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ] - }, - "snowfallLo": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Low end of the spread across models / members; null for a single model." - }, - "tempMax": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "°C as the models report it." - }, - "tempMin": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ] - }, - "weatherCode": { - "anyOf": [ - { - "maximum": 9007199254740991, - "minimum": -9007199254740991, - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "WMO weather interpretation code." - }, - "windGust": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "km/h." - } - }, - "required": [ - "date", - "snowfallCm", - "snowfallLo", - "snowfallHi", - "tempMax", - "tempMin", - "precipProb", - "windGust", - "weatherCode" - ], - "type": "object" - }, - "type": "array" - }, - "horizonDays": { - "maximum": 9007199254740991, - "minimum": -9007199254740991, - "type": "integer" - }, - "id": { - "type": "string" - }, - "issuedAt": { - "type": "string" - }, - "model": { - "description": "Model id as the provider names it, or `blend` for PeakCam's skill-weighted blend.", - "type": "string" - }, - "point": { - "enum": [ - "summit", - "base" - ], - "type": "string" - } - }, - "required": [ - "id", - "point", - "model", - "issuedAt", - "horizonDays", - "days" - ], - "type": "object" -} - removed
Output schema / properties / forecast / typeRemoved value: -"array" - changed
Output schema / properties / forecastScores / descriptionPrevious value: -"Per-model verification at this resort, once computed."New value: +"Per-model verification at this resort over 90 days, ranked; empty until the scorer has measured days. Detail at `/resorts/{slug}/forecast-accuracy`." - added
Output schema / properties / forecastScores / items / properties / rankAdded value: +{ + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "1 = lowest day-1 MAE among the models scored at this resort (the blend is ranked too). Null before the first scoring run." +} - changed
Output schema / properties / forecastScores / items / requiredPrevious value: -[ - "model", - "periodDays", - "day1Mae", - "day3Mae", - "day7Mae", - "samples", - "biasRatio", - "computedAt" -]New value: +[ + "model", + "periodDays", + "day1Mae", + "day3Mae", + "day7Mae", + "samples", + "biasRatio", + "computedAt", + "rank" +]
- Added
get_season_stats - Changed
get_snow_history5 fields changed- changed
Input schema / properties / days / descriptionPrevious value: -"Days back, 1–30."New value: +"Days back, 1–30. Ignored when `season` is set." - added
Input schema / properties / seasonAdded value: +{ + "description": "A season label (`2024-25` for the Northern water year, `2026` for an Andes resort) or `current`: returns every daily row of that season, oldest first, with daily new snow.", + "pattern": "^(current|\\d{4}(-\\d{2})?)$", + "type": "string" +} - added
Output schema / properties / rows / items / properties / newSnowInAdded value: +{ + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Daily new snow (positive depth change), season reads only." +} - added
Output schema / properties / seasonAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "The season label when `season` was asked for; null for a last-N-days read." +} - changed
Output schema / requiredPrevious value: -[ - "slug", - "name", - "canonicalUrl", - "source", - "station", - "days", - "count", - "rows", - "generatedAt" -]New value: +[ + "slug", + "name", + "canonicalUrl", + "source", + "station", + "days", + "season", + "count", + "rows", + "generatedAt" +]
3 tool updates
- Changed
compare_resorts12 fields changed- added
Output schema / properties / resorts / items / properties / measuredNow / items / properties / ageMinutesAdded value: +{ + "description": "Minutes between `observedAt` and `generatedAt`. Daily sources read 1,440 or more; hourly sources under 120 when live.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" +} - added
Output schema / properties / resorts / items / properties / measuredNow / items / properties / attributionAdded value: +{ + "description": "The credit line the provider's terms ask for.", + "type": "string" +} - added
Output schema / properties / resorts / items / properties / measuredNow / items / properties / distanceKmAdded value: +{ + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Great-circle distance from the resort's coordinates." +} - added
Output schema / properties / resorts / items / properties / measuredNow / items / properties / elevationFtAdded value: +{ + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Station elevation. Every value below describes this elevation." +} - added
Output schema / properties / resorts / items / properties / measuredNow / items / properties / nameAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] +} - changed
Output schema / properties / resorts / items / properties / measuredNow / items / properties / newSnowIn / descriptionPrevious value: -"New snow since the previous observation, inches."New value: +"New snow over the provider's own period (24 h for daily sources), inches. Null for hourly sources, which do not measure it." - changed
Output schema / properties / resorts / items / properties / measuredNow / items / properties / observedAt / descriptionPrevious value: -"ISO-8601 instant of the observation."New value: +"ISO-8601 instant of the observation; a daily value is stamped at the end of its UTC day." - added
Output schema / properties / resorts / items / properties / measuredNow / items / properties / roleAdded value: +{ + "description": "summit / mid / base by the station's elevation against the resort's vertical.", + "enum": [ + "summit", + "mid", + "base", + "approach" + ], + "type": "string" +} - added
Output schema / properties / resorts / items / properties / measuredNow / items / properties / sourceAdded value: +{ + "enum": [ + "snotel", + "ghcn", + "nws", + "bc_asws", + "eccc" + ], + "type": "string" +} - added
Output schema / properties / resorts / items / properties / measuredNow / items / properties / sourceIdAdded value: +{ + "description": "The provider's own station id, e.g. `AMB`, `1308:UT:SNTL`, `USC00420072`.", + "type": "string" +} - added
Output schema / properties / resorts / items / properties / measuredNow / items / properties / stationId / descriptionAdded value: +"PeakCam station id; joins `stations[]`." - changed
Output schema / properties / resorts / items / properties / measuredNow / items / requiredPrevious value: -[ - "stationId", - "observedAt", - "snowDepthIn", - "sweIn", - "newSnowIn", - "tempF", - "windMph" -]New value: +[ + "stationId", + "role", + "source", + "sourceId", + "name", + "elevationFt", + "distanceKm", + "observedAt", + "ageMinutes", + "snowDepthIn", + "sweIn", + "newSnowIn", + "tempF", + "windMph", + "attribution" +]
- Changed
get_resort_conditions12 fields changed- added
Output schema / properties / measuredNow / items / properties / ageMinutesAdded value: +{ + "description": "Minutes between `observedAt` and `generatedAt`. Daily sources read 1,440 or more; hourly sources under 120 when live.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" +} - added
Output schema / properties / measuredNow / items / properties / attributionAdded value: +{ + "description": "The credit line the provider's terms ask for.", + "type": "string" +} - added
Output schema / properties / measuredNow / items / properties / distanceKmAdded value: +{ + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Great-circle distance from the resort's coordinates." +} - added
Output schema / properties / measuredNow / items / properties / elevationFtAdded value: +{ + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Station elevation. Every value below describes this elevation." +} - added
Output schema / properties / measuredNow / items / properties / nameAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] +} - changed
Output schema / properties / measuredNow / items / properties / newSnowIn / descriptionPrevious value: -"New snow since the previous observation, inches."New value: +"New snow over the provider's own period (24 h for daily sources), inches. Null for hourly sources, which do not measure it." - changed
Output schema / properties / measuredNow / items / properties / observedAt / descriptionPrevious value: -"ISO-8601 instant of the observation."New value: +"ISO-8601 instant of the observation; a daily value is stamped at the end of its UTC day." - added
Output schema / properties / measuredNow / items / properties / roleAdded value: +{ + "description": "summit / mid / base by the station's elevation against the resort's vertical.", + "enum": [ + "summit", + "mid", + "base", + "approach" + ], + "type": "string" +} - added
Output schema / properties / measuredNow / items / properties / sourceAdded value: +{ + "enum": [ + "snotel", + "ghcn", + "nws", + "bc_asws", + "eccc" + ], + "type": "string" +} - added
Output schema / properties / measuredNow / items / properties / sourceIdAdded value: +{ + "description": "The provider's own station id, e.g. `AMB`, `1308:UT:SNTL`, `USC00420072`.", + "type": "string" +} - added
Output schema / properties / measuredNow / items / properties / stationId / descriptionAdded value: +"PeakCam station id; joins `stations[]`." - changed
Output schema / properties / measuredNow / items / requiredPrevious value: -[ - "stationId", - "observedAt", - "snowDepthIn", - "sweIn", - "newSnowIn", - "tempF", - "windMph" -]New value: +[ + "stationId", + "role", + "source", + "sourceId", + "name", + "elevationFt", + "distanceKm", + "observedAt", + "ageMinutes", + "snowDepthIn", + "sweIn", + "newSnowIn", + "tempF", + "windMph", + "attribution" +]
- Added
get_stations
6 tool updates
- Added
ask - Added
get_alert_options - Added
get_cam_timeline - Added
get_percent_of_normal - Added
get_resort_profile - Added
list_regions
3 tool updates
- Changed
compare_resorts9 fields changed- added
Output schema / properties / resorts / items / properties / forecastAdded value: +{ + "description": "Latest run per model and point, once stored forecasts are live.", + "items": { + "additionalProperties": false, + "properties": { + "days": { + "items": { + "additionalProperties": false, + "properties": { + "date": { + "description": "YYYY-MM-DD, local to the resort.", + "type": "string" + }, + "precipProb": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "0–100." + }, + "snowfallCm": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "snowfallHi": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "snowfallLo": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Low end of the spread across models / members; null for a single model." + }, + "tempMax": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "°C as the models report it." + }, + "tempMin": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "weatherCode": { + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "WMO weather interpretation code." + }, + "windGust": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "km/h." + } + }, + "required": [ + "date", + "snowfallCm", + "snowfallLo", + "snowfallHi", + "tempMax", + "tempMin", + "precipProb", + "windGust", + "weatherCode" + ], + "type": "object" + }, + "type": "array" + }, + "horizonDays": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "id": { + "type": "string" + }, + "issuedAt": { + "type": "string" + }, + "model": { + "description": "Model id as the provider names it, or `blend` for PeakCam's skill-weighted blend.", + "type": "string" + }, + "point": { + "enum": [ + "summit", + "base" + ], + "type": "string" + } + }, + "required": [ + "id", + "point", + "model", + "issuedAt", + "horizonDays", + "days" + ], + "type": "object" + }, + "type": "array" +} - added
Output schema / properties / resorts / items / properties / forecastScoresAdded value: +{ + "description": "Per-model verification at this resort, once computed.", + "items": { + "additionalProperties": false, + "properties": { + "biasRatio": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Sum(forecast) / sum(observed); above 1 means the model over-forecasts snow." + }, + "computedAt": { + "type": "string" + }, + "day1Mae": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Mean absolute error of the day-1 snowfall forecast, cm." + }, + "day3Mae": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "day7Mae": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "model": { + "type": "string" + }, + "periodDays": { + "description": "Trailing verification window, days.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "samples": { + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "model", + "periodDays", + "day1Mae", + "day3Mae", + "day7Mae", + "samples", + "biasRatio", + "computedAt" + ], + "type": "object" + }, + "type": "array" +} - added
Output schema / properties / resorts / items / properties / location / properties / summitElevationFtAdded value: +{ + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] +} - changed
Output schema / properties / resorts / items / properties / location / requiredPrevious value: -[ - "state", - "region", - "country", - "lat", - "lon", - "baseElevationFt" -]New value: +[ + "state", + "region", + "country", + "lat", + "lon", + "baseElevationFt", + "summitElevationFt" +] - added
Output schema / properties / resorts / items / properties / measuredNowAdded value: +{ + "description": "Latest observation per station, once the station layer is live.", + "items": { + "additionalProperties": false, + "properties": { + "newSnowIn": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "New snow since the previous observation, inches." + }, + "observedAt": { + "description": "ISO-8601 instant of the observation.", + "type": "string" + }, + "snowDepthIn": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "stationId": { + "type": "string" + }, + "sweIn": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "tempF": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "windMph": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "stationId", + "observedAt", + "snowDepthIn", + "sweIn", + "newSnowIn", + "tempF", + "windMph" + ], + "type": "object" + }, + "type": "array" +} - added
Output schema / properties / resorts / items / properties / profileAdded value: +{ + "additionalProperties": false, + "properties": { + "aliases": { + "description": "Other names the resort is known by, e.g. `A-Basin`.", + "items": { + "type": "string" + }, + "type": "array" + }, + "annualSnowfallIn": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Operator-stated average annual snowfall, inches." + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "descriptionSource": { + "anyOf": [ + { + "enum": [ + "operator", + "generated", + "editor" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "description": "`operator`: the resort's own copy. `generated`: a model-written draft, labelled as such on the page. `editor`: hand-written by PeakCam." + }, + "liftsTotal": { + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ] + }, + "longestRunMi": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "passes": { + "description": "Multi-resort passes the resort is on.", + "items": { + "enum": [ + "ikon", + "epic", + "mountain-collective", + "indy", + "power" + ], + "type": "string" + }, + "type": "array" + }, + "runsTotal": { + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ] + }, + "skiableAcres": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "trailMapUrl": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "The operator's trail map (linked, never copied)." + }, + "verticalFt": { + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ] + }, + "wikidataId": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "runsTotal", + "liftsTotal", + "skiableAcres", + "verticalFt", + "annualSnowfallIn", + "longestRunMi", + "description", + "descriptionSource", + "trailMapUrl", + "wikidataId", + "aliases", + "passes" + ], + "type": "object" +} - added
Output schema / properties / resorts / items / properties / scoreAdded value: +{ + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "components": { + "additionalProperties": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "date": { + "description": "YYYY-MM-DD the score is for.", + "type": "string" + }, + "rating": { + "anyOf": [ + { + "enum": [ + "great", + "good", + "fair", + "poor" + ], + "type": "string" + }, + { + "type": "null" + } + ] + }, + "score": { + "maximum": 100, + "minimum": 0, + "type": "integer" + }, + "scoredBy": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Scorer version, e.g. `score-v1`." + } + }, + "required": [ + "date", + "score", + "rating", + "components", + "scoredBy" + ], + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Today's 0–100 score, once the scorer is live." +} - added
Output schema / properties / resorts / items / properties / stationsAdded value: +{ + "description": "Observation stations serving the resort, once the station layer is live.", + "items": { + "additionalProperties": false, + "properties": { + "distanceKm": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Great-circle distance from the resort's coordinates." + }, + "elevationFt": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "id": { + "description": "PeakCam station id (UUID).", + "type": "string" + }, + "kind": { + "enum": [ + "snotel", + "scan", + "nws_obs", + "metar", + "ghcn", + "bc_asws", + "eccc", + "road_cam" + ], + "type": "string" + }, + "lat": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "lon": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "rank": { + "description": "1 = the preferred station for its role.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "role": { + "description": "Where the station sits relative to the resort.", + "enum": [ + "summit", + "mid", + "base", + "approach" + ], + "type": "string" + }, + "source": { + "description": "Provider, e.g. `nrcs`, `nws`, `eccc`, `udot`.", + "type": "string" + }, + "sourceId": { + "description": "The provider's own identifier (SNOTEL triplet, ICAO code, GHCN id).", + "type": "string" + } + }, + "required": [ + "id", + "source", + "sourceId", + "name", + "kind", + "role", + "lat", + "lon", + "elevationFt", + "distanceKm", + "rank" + ], + "type": "object" + }, + "type": "array" +} - changed
Output schema / properties / resorts / items / requiredPrevious value: -[ - "slug", - "name", - "canonicalUrl", - "apiUrl", - "location", - "snow", - "season", - "websiteUrl", - "attribution", - "license", - "updatedAt", - "camCount", - "liveCamCount" -]New value: +[ + "slug", + "name", + "canonicalUrl", + "apiUrl", + "location", + "profile", + "snow", + "season", + "websiteUrl", + "attribution", + "license", + "updatedAt", + "camCount", + "liveCamCount" +]
- Changed
get_resort_cams5 fields changed- added
Output schema / properties / cams / items / properties / creditAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Attribution line to show with the frame. Null means credit the resort." +} - added
Output schema / properties / cams / items / properties / kindAdded value: +{ + "anyOf": [ + { + "enum": [ + "summit", + "mid", + "base", + "snow-stake", + "village", + "approach" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "description": "What the cam looks at. Null when not classified." +} - added
Output schema / properties / cams / items / properties / sourceTermsUrlAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "The operator's terms governing reuse of this feed, when known." +} - added
Output schema / properties / cams / items / properties / timelapsesAdded value: +{ + "description": "Rendered clips, once PeakCam renders them for this cam.", + "items": { + "additionalProperties": false, + "properties": { + "frames": { + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ] + }, + "id": { + "type": "string" + }, + "renderedAt": { + "description": "ISO-8601 instant the clip was rendered.", + "type": "string" + }, + "stormDate": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "YYYY-MM-DD of the storm a `storm` clip covers." + }, + "url": { + "description": "Public MP4 URL.", + "type": "string" + }, + "window": { + "description": "Which clip: `24h` (rolling day), `storm` (one storm, see `stormDate`), or another label.", + "type": "string" + } + }, + "required": [ + "id", + "window", + "url", + "frames", + "renderedAt", + "stormDate" + ], + "type": "object" + }, + "type": "array" +} - changed
Output schema / properties / cams / items / requiredPrevious value: -[ - "id", - "name", - "elevation", - "live", - "lastCheckedAt", - "stillUrl", - "capturedAt", - "embedType", - "pageUrl", - "sourceUrl" -]New value: +[ + "id", + "name", + "elevation", + "live", + "lastCheckedAt", + "stillUrl", + "capturedAt", + "embedType", + "pageUrl", + "sourceUrl", + "kind", + "credit", + "sourceTermsUrl" +]
- Changed
get_resort_conditions14 fields changed- added
Output schema / properties / cams / items / properties / creditAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Attribution line to show with the frame. Null means credit the resort." +} - added
Output schema / properties / cams / items / properties / kindAdded value: +{ + "anyOf": [ + { + "enum": [ + "summit", + "mid", + "base", + "snow-stake", + "village", + "approach" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "description": "What the cam looks at. Null when not classified." +} - added
Output schema / properties / cams / items / properties / sourceTermsUrlAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "The operator's terms governing reuse of this feed, when known." +} - added
Output schema / properties / cams / items / properties / timelapsesAdded value: +{ + "description": "Rendered clips, once PeakCam renders them for this cam.", + "items": { + "additionalProperties": false, + "properties": { + "frames": { + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ] + }, + "id": { + "type": "string" + }, + "renderedAt": { + "description": "ISO-8601 instant the clip was rendered.", + "type": "string" + }, + "stormDate": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "YYYY-MM-DD of the storm a `storm` clip covers." + }, + "url": { + "description": "Public MP4 URL.", + "type": "string" + }, + "window": { + "description": "Which clip: `24h` (rolling day), `storm` (one storm, see `stormDate`), or another label.", + "type": "string" + } + }, + "required": [ + "id", + "window", + "url", + "frames", + "renderedAt", + "stormDate" + ], + "type": "object" + }, + "type": "array" +} - changed
Output schema / properties / cams / items / requiredPrevious value: -[ - "id", - "name", - "elevation", - "live", - "lastCheckedAt", - "stillUrl", - "capturedAt", - "embedType", - "pageUrl", - "sourceUrl" -]New value: +[ + "id", + "name", + "elevation", + "live", + "lastCheckedAt", + "stillUrl", + "capturedAt", + "embedType", + "pageUrl", + "sourceUrl", + "kind", + "credit", + "sourceTermsUrl" +] - added
Output schema / properties / forecastAdded value: +{ + "description": "Latest run per model and point, once stored forecasts are live.", + "items": { + "additionalProperties": false, + "properties": { + "days": { + "items": { + "additionalProperties": false, + "properties": { + "date": { + "description": "YYYY-MM-DD, local to the resort.", + "type": "string" + }, + "precipProb": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "0–100." + }, + "snowfallCm": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "snowfallHi": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "snowfallLo": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Low end of the spread across models / members; null for a single model." + }, + "tempMax": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "°C as the models report it." + }, + "tempMin": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "weatherCode": { + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "WMO weather interpretation code." + }, + "windGust": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "km/h." + } + }, + "required": [ + "date", + "snowfallCm", + "snowfallLo", + "snowfallHi", + "tempMax", + "tempMin", + "precipProb", + "windGust", + "weatherCode" + ], + "type": "object" + }, + "type": "array" + }, + "horizonDays": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "id": { + "type": "string" + }, + "issuedAt": { + "type": "string" + }, + "model": { + "description": "Model id as the provider names it, or `blend` for PeakCam's skill-weighted blend.", + "type": "string" + }, + "point": { + "enum": [ + "summit", + "base" + ], + "type": "string" + } + }, + "required": [ + "id", + "point", + "model", + "issuedAt", + "horizonDays", + "days" + ], + "type": "object" + }, + "type": "array" +} - added
Output schema / properties / forecastScoresAdded value: +{ + "description": "Per-model verification at this resort, once computed.", + "items": { + "additionalProperties": false, + "properties": { + "biasRatio": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Sum(forecast) / sum(observed); above 1 means the model over-forecasts snow." + }, + "computedAt": { + "type": "string" + }, + "day1Mae": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Mean absolute error of the day-1 snowfall forecast, cm." + }, + "day3Mae": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "day7Mae": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "model": { + "type": "string" + }, + "periodDays": { + "description": "Trailing verification window, days.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "samples": { + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "model", + "periodDays", + "day1Mae", + "day3Mae", + "day7Mae", + "samples", + "biasRatio", + "computedAt" + ], + "type": "object" + }, + "type": "array" +} - added
Output schema / properties / location / properties / summitElevationFtAdded value: +{ + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] +} - changed
Output schema / properties / location / requiredPrevious value: -[ - "state", - "region", - "country", - "lat", - "lon", - "baseElevationFt" -]New value: +[ + "state", + "region", + "country", + "lat", + "lon", + "baseElevationFt", + "summitElevationFt" +] - added
Output schema / properties / measuredNowAdded value: +{ + "description": "Latest observation per station, once the station layer is live.", + "items": { + "additionalProperties": false, + "properties": { + "newSnowIn": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "New snow since the previous observation, inches." + }, + "observedAt": { + "description": "ISO-8601 instant of the observation.", + "type": "string" + }, + "snowDepthIn": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "stationId": { + "type": "string" + }, + "sweIn": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "tempF": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "windMph": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "stationId", + "observedAt", + "snowDepthIn", + "sweIn", + "newSnowIn", + "tempF", + "windMph" + ], + "type": "object" + }, + "type": "array" +} - added
Output schema / properties / profileAdded value: +{ + "additionalProperties": false, + "properties": { + "aliases": { + "description": "Other names the resort is known by, e.g. `A-Basin`.", + "items": { + "type": "string" + }, + "type": "array" + }, + "annualSnowfallIn": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Operator-stated average annual snowfall, inches." + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "descriptionSource": { + "anyOf": [ + { + "enum": [ + "operator", + "generated", + "editor" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "description": "`operator`: the resort's own copy. `generated`: a model-written draft, labelled as such on the page. `editor`: hand-written by PeakCam." + }, + "liftsTotal": { + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ] + }, + "longestRunMi": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "passes": { + "description": "Multi-resort passes the resort is on.", + "items": { + "enum": [ + "ikon", + "epic", + "mountain-collective", + "indy", + "power" + ], + "type": "string" + }, + "type": "array" + }, + "runsTotal": { + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ] + }, + "skiableAcres": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "trailMapUrl": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "The operator's trail map (linked, never copied)." + }, + "verticalFt": { + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ] + }, + "wikidataId": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "runsTotal", + "liftsTotal", + "skiableAcres", + "verticalFt", + "annualSnowfallIn", + "longestRunMi", + "description", + "descriptionSource", + "trailMapUrl", + "wikidataId", + "aliases", + "passes" + ], + "type": "object" +} - added
Output schema / properties / scoreAdded value: +{ + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "components": { + "additionalProperties": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "date": { + "description": "YYYY-MM-DD the score is for.", + "type": "string" + }, + "rating": { + "anyOf": [ + { + "enum": [ + "great", + "good", + "fair", + "poor" + ], + "type": "string" + }, + { + "type": "null" + } + ] + }, + "score": { + "maximum": 100, + "minimum": 0, + "type": "integer" + }, + "scoredBy": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Scorer version, e.g. `score-v1`." + } + }, + "required": [ + "date", + "score", + "rating", + "components", + "scoredBy" + ], + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Today's 0–100 score, once the scorer is live." +} - added
Output schema / properties / stationsAdded value: +{ + "description": "Observation stations serving the resort, once the station layer is live.", + "items": { + "additionalProperties": false, + "properties": { + "distanceKm": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Great-circle distance from the resort's coordinates." + }, + "elevationFt": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "id": { + "description": "PeakCam station id (UUID).", + "type": "string" + }, + "kind": { + "enum": [ + "snotel", + "scan", + "nws_obs", + "metar", + "ghcn", + "bc_asws", + "eccc", + "road_cam" + ], + "type": "string" + }, + "lat": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "lon": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "rank": { + "description": "1 = the preferred station for its role.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "role": { + "description": "Where the station sits relative to the resort.", + "enum": [ + "summit", + "mid", + "base", + "approach" + ], + "type": "string" + }, + "source": { + "description": "Provider, e.g. `nrcs`, `nws`, `eccc`, `udot`.", + "type": "string" + }, + "sourceId": { + "description": "The provider's own identifier (SNOTEL triplet, ICAO code, GHCN id).", + "type": "string" + } + }, + "required": [ + "id", + "source", + "sourceId", + "name", + "kind", + "role", + "lat", + "lon", + "elevationFt", + "distanceKm", + "rank" + ], + "type": "object" + }, + "type": "array" +} - changed
Output schema / requiredPrevious value: -[ - "slug", - "name", - "canonicalUrl", - "apiUrl", - "location", - "snow", - "season", - "cams", - "websiteUrl", - "attribution", - "license", - "updatedAt" -]New value: +[ + "slug", + "name", + "canonicalUrl", + "apiUrl", + "location", + "profile", + "snow", + "season", + "cams", + "websiteUrl", + "attribution", + "license", + "updatedAt" +]
8 tool updates
- First observed
compare_resorts - First observed
find_powder - First observed
get_forecast - First observed
get_opening_dates - First observed
get_resort_cams - First observed
get_resort_conditions - First observed
get_snow_history - First observed
search_resorts
Related MCP Connectors
Live verified resort snow, forecasts, powder search, trip planning & grounded Q&A for 430+ resorts.
Free 15-day snow forecasts and conditions for 667 ski resorts in North America and Japan.
Live ski snow, multi-model forecasts, powder rankings & a grounded Answer Engine for 500+ resorts.
Ski resort conditions, forecasts, avalanche danger, sun, routes and snow history for 5,000+ resorts.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceEnables users to search ski resorts, retrieve up to 15-day snow forecasts and current conditions, compare or rank resorts for powder and trip planning, and access opening dates, lift status, resort news, and station-verified forecast accuracy across 667 ski resorts.MIT
- AlicenseAqualityDmaintenanceLive ski & snow data for AI agents: 14-day multi-model forecasts, powder rankings, resort guides, webcams, ski-pass intelligence, and avalanche/road safety across 500+ resorts. Hosted streamable-HTTP — no install, no auth.401MIT
- AlicenseNot gradedqualityDmaintenanceProvides access to real-time and historical snow conditions, weather data, and snowpack analysis from over 800 SNOTEL stations across the western United States through the USDA Air and Water Database API.2MIT
- FlicenseNot gradedqualityDmaintenanceEnables users to find the best ski resort snow conditions worldwide and search for flights to get there.-
Glama MCP Gateway
Add one secure layer between your agents and this server.