MCP server exposing osu! API v2 as tools for Claude and other MCP clients
osu-mcp demonstrates solid tool design with consistent naming (verb_noun pattern), comprehensive parameter schemas, and clear descriptions. All 12 tools follow the get_/search_ convention. Schemas are well-structured with proper types, enums, and constraints (e.g., difficulty_range, bpm_range as tuples; mode as enum). Descriptions average ~120 chars, meeting the 10-1024 baseline. However, output schemas are not documented, LLMs cannot predict response structure. Error handling exists but lacks recovery guidance. No tool annotations (readOnlyHint, idempotentHint) despite all tools being read-only. Parameter descriptions are present but could be more prescriptive about constraints (e.g., 'ISO 3166-1 alpha-2' is stated but not validated in description).
Side-by-side comparison of 2-5 osu! users on the chosen metrics. Useful for 'how do I stack up against X' or 'top N hispanics' analyses.
Get a beatmap by ID with difficulty attributes (AR/OD/CS/HP, BPM, length).
Get top scores on a specific beatmap. Filter by mods (HD/HR/DT/etc) and mode (defaults to map's mode).
Get a full beatmapset (all difficulties) by set ID.
Shortcut: top N players of a country in pp ranking for a given mode. country_code is ISO 3166-1 alpha-2 (e.g., 'EC' for Ecuador, 'JP' for Japan).
Get recent osu! news posts. Useful for tracking meta announcements, ranked updates, tournament summaries. Optionally filter by year.
Output schemas not documented. LLMs cannot predict response structure (fields, types, nested objects). Agents must infer from trial-and-error or context.
No tool annotations (readOnlyHint, idempotentHint). All 12 tools are read-only and idempotent, but LLMs cannot infer this without explicit hints. Agents may incorrectly treat them as stateful.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 61 | <=2025-11-25 | v2 |
Get osu! rankings. type='performance' (global/country pp leaderboard), 'score', or 'charts' (monthly tournaments). Filter by `country` (ISO 3166-1 alpha-2).
Fetch a specific score by ID and mode, with full attributes.
Get currently active seasonal backgrounds (rotates ~quarterly).
List a user's scores by type: 'best' (top by pp), 'recent' (last 24h), or 'firsts' (#1 placements). Returns up to `limit` scores (1-100).
Get an osu! user's profile + stats. user_id_or_name can be numeric ID or username. Optionally embed recent/best/firsts scores via the include list.
Search beatmapsets by query string with optional filters: mode, status, difficulty/length/bpm ranges. Returns up to `limit` (default 20, max 50).
Error handling lacks recovery guidance. ValidationError and OsuMcpError are caught but responses do not suggest next steps (e.g., 'User not found. Try search_users() first.').
Parameter descriptions lack prescriptive constraints. E.g., 'ISO 3166-1 alpha-2 country code (length 2)' is stated but validation rules are not explicit in description text. LLMs may pass invalid codes.
get_seasonal_backgrounds has minimal description (60 chars). 'Get currently active seasonal backgrounds (rotates ~quarterly).' lacks context on when to call it or what structure it returns.