MCP server for StadiaPass ticket management system, providing read-only access to match catalogue, seat availability, revenue analytics, and staff policy documents
StadiaPass demonstrates solid tool design with clear naming, comprehensive descriptions, and proper schema definitions. All 5 tools follow verb_noun patterns (get_*, search_*). Descriptions are detailed (150-250 chars), explaining WHAT the tool does, WHEN to use it, and key caveats (e.g., 'Seats sell continuously, so a count from earlier in a conversation is out of date'). Input schemas are properly typed with descriptions. However, output schemas are not explicitly documented in the visible code, responses are wrapped in generic Reading<T> or result objects without field-level documentation. Error handling is minimal: tools throw McpException on failures but do not provide recovery guidance or actionable next steps. No tool annotations (readOnlyHint, destructiveHint) are visible, despite all tools being read-only. Parameter descriptions are strong but could benefit from explicit constraints (e.g., limit range for search_policies).
Reports what one match has taken: tickets sold and their net revenue, tickets refunded and the amount given back, plus capacity, seats sold and occupancy - under 'result', with the moment the figures were read under 'asOfUtc'. Takings rise with every sale, so a figure from earlier in a conversation is out of date. Net revenue already excludes refunded tickets - do not subtract them again. Use a match id from get_upcoming_matches or search_matches. Staff-facing figures, not for quoting to customers.
Summarises seat availability for one match: total seats left, the cheapest available price, and per-block counts with price ranges, under 'result', with the moment they were read under 'asOfUtc'. Seats sell continuously, so a count from earlier in a conversation is out of date. Use a match id from get_upcoming_matches or search_matches. This is a summary on purpose - seat-by-seat choice happens on the seat map in the web UI.
Lists the upcoming matches currently on sale, soonest kick-off first, with seat availability counts. Optionally filtered to one sport category. The listing comes back under 'result' and the moment it was read under 'asOfUtc'.
Free-text search over the matches on sale - team, venue, city or sport - most relevant first, under 'result', with the moment they were read under 'asOfUtc'. When 'searchAvailable' is false in the answer, the search index could not be reached and the matches given are the plain upcoming listing instead of real search results: say so.
Output schemas not documented. Tools return Reading<T>, MatchRevenue, PolicySearchResult, etc., but field-level structure is not visible in tool definitions. LLMs cannot plan downstream calls or extract specific fields without guessing.
Error handling lacks recovery guidance. Tools throw McpException('No match with id {matchId} exists.') but do not suggest next steps (e.g., 'Try search_matches() to find valid match IDs'). Agents cannot self-correct.
Tool annotations missing. All tools are read-only but do not declare readOnlyHint=true. This forces LLMs to infer safety from descriptions rather than machine-readable metadata.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 60 | 2026-07-28+ | v2 |
Finds the sections of the staff policy documents nearest to a question - refund rules, seat holds, sales conditions, who may do what, stadium entry - under 'hits', nearest first, each with the document, its title, the section heading, the section text and a similarity score. There is always a nearest section: a low score or a section about a nearby topic means the documents may not cover the question, so answer only from what the text actually says and say when it does not. Staff-facing rules, not for quoting to customers verbatim.
Parameter constraints not explicit. search_policies accepts 'limit' with default=3 but no min/max bounds documented. LLMs could pass 0, -1, or 10000 without validation guidance.
Pagination not implemented. get_upcoming_matches and search_matches return lists but lack offset/limit/cursor parameters. Large result sets could exhaust context windows.