Solar Vitamin D Explorer - Know when and where you can synthesize Vitamin D
The server demonstrates solid definition quality with 15 well-named tools covering a specialized domain (vitamin D synthesis modeling). All tools have descriptions ranging from 40 - 300 characters and input schemas with type declarations. However, several issues prevent a higher score: (1) no output schemas are documented anywhere, callers cannot predict response structure; (2) error handling is absent from tool definitions; (3) only 3 of 15 tools have fully enumerated parameters with constraints; (4) write-side tools (log_sun_session, update_my_profile, set_history_location) lack confirmation or idempotency markers. The codebase is clean and TypeScript-typed, but the MCP layer lacks production-grade schema rigor. Average per-tool score is 72/100.
Two locations side-by-side: the year grid for each, a profile line beneath the grids, and a verdict row underneath all of it — how many days each had a window, their averages, and whether one is "better" for vitamin D than the other.
Change skin type, exposed area, age, or target IU and see the effect on the vitamin D window and the year grid.
Estimate how much vitamin D the user will synthesize in a given session based on time spent outside, skin type, exposed area, and weather.
Right now: is the window open, and if so, how long until it closes and how much IU can the user absorb before then.
Get the authenticated user's favorite cities and custom locations.
Get the authenticated user's sun exposure history: dates, locations, and whether viable vitamin D synthesis occurred.
No output schemas documented. Tool descriptions never specify what fields/structure callers should expect. Without response schemas, LLMs cannot plan downstream calls or extract required data for chaining (e.g., what does get_vitamin_d_year return? Is it an array, a table, a summary object?).
No error handling guidance. Tool definitions lack any hint about what errors can occur, how to categorize them (retryable, user-fixable, fatal), or what recovery steps the LLM should take. If a tool fails (e.g., invalid latitude, timezone not found), the agent has no recovery path.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | C | 62 | 2026-07-28+ | v2 |
Get the authenticated user's vitamin D profile: skin type, exposed skin fraction, age, and target IU.
Clear-sky UV at a local hour, from the day's elevation curve. A local hour as "HH:MM". Bounds are fractional on the clear-sky path.
The whole year broken into viable-sun stretches: on each date, was the window present, and if so, how long and how intense. For each city separately: the best hour, the peak clear-sky UV, how many minutes at that hour to hit the target, and how much IU the body would absorb at the max. A grid: rows are months, columns are days, cells shade by that day's verdict.
The whole year broken into viable-sun stretches: on each date, was the window present, and if so, how long and how intense.
Log a sun exposure session for the authenticated user: date, location, duration, and whether synthesis was viable.
Match against the built-in city DB: Spanish base names + the six locales' URL slugs, so "London", "Londres" and "londonas" all find the same city.
Set the location context for sun exposure history logging.
7-day forecast of cloud cover from the European model, and vitamin D windows per day — the best hours to catch the sun.
Update the authenticated user's vitamin D profile: skin type, exposed skin fraction, age, or target IU.
No parameter constraints (enums, ranges). Tools like get_vitamin_d_window accept skinType (1 - 6), exposedSkinFraction (0 - 1), and age (0 - 120) but lack min/max bounds or enum declarations. LLMs can pass invalid values (skinType=99, exposedSkinFraction=5.0) without being told what values are valid.
Write-side tools lack idempotency or confirmation markers. log_sun_session, update_my_profile, and set_history_location can modify user state. No tool annotations (idempotentHint, destructiveHint) warn the LLM that retries may cause duplicate records or unintended state changes.
Trivial descriptions for user-specific tools. get_my_profile, get_my_cities, and get_my_history each have ~60-char descriptions that are too short to guide LLM selection. E.g., 'Get the authenticated user's vitamin D profile' says WHAT but not WHEN to call it or what it returns.
Parameter descriptions lack format/constraint guidance. E.g., date parameters accept 'YYYY-MM-DD' but descriptions don't state the format explicitly. timezone description says 'IANA timezone like Europe/Madrid', good, but others like exposedSkinFraction lack bounds ('0.10 to 0.40'). LLMs cannot validate without formal constraints or explicit text guidance.