The Oura v2 API as an MCP server. Paginates, fixes the date range, warns when data is missing.
oura-mcp presents well-structured tool definitions with clear naming conventions and detailed descriptions. All four tools follow verb_noun patterns (oura_collections, oura_query, oura_today, oura_check) and carry comprehensive docstrings (194-400+ chars). Input schemas are fully visible and properly typed with JSON Schema. Tool annotations are correctly declared (_SOLO_LECTURA pattern with read_only_hint=True, idempotent_hint=True, open_world_hint=True). However, there are gaps in parameter-level descriptions and output schema documentation. The server demonstrates mature thinking about composition (four tools, not nineteen) and proper error recovery guidance, but lacks explicit pagination/limit documentation in some tools and does not document the shape of returned objects.
Which credential you're using, which scopes you have, and whether Oura responds. Shows neither the token nor any health value. Does not touch Oura unless there is a real credential (sandbox or token or OAuth2); without one it says so cleanly.
The 19 Oura collections, what each one carries and which parameters it takes. Use it before `oura_query` if you are unsure of the exact name.
Fetches a COMPLETE Oura collection over the requested range. Follows pagination to the end: Oura returns `next_token` and whoever doesn't chase it receives the first page with nothing saying so. One local day of `heartrate` is 1,231 samples across 2 pages. The range is INCLUSIVE on both ends. Oura does not behave that way — some collections exclude the last day and others don't, and `workout` is skewed to UTC — but that is corrected here.
The shorthand for `oura_query` with `day=today`. Exactly equivalent to requesting the current calendar day; it saves a parameter and a decision on the caller's side, and the response carries the same `synthetic`, `empty`, `large_response` flags as `oura_query`.
Output schema not explicitly documented in tool descriptions. Tools return structured responses (synthetic, empty, large_response flags mentioned) but the exact shape is not described, forcing LLMs to infer response structure.
Pagination limits and defaults not documented in parameter descriptions. 'fields' parameter accepts array|string|null but the implications of null are not explained (does it return all fields? only defaults?). 'format' defaults to 'json' but behavior on CSV with certain queries is not specified.
The 'latest' parameter on oura_query has a note 'heartrate and ring_battery_level only' but this is a usage constraint, not a parameter description. If called on other collections, behavior is undefined (does it error gracefully? silently ignore?).
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | B | 72 | 2026-07-28+ | v2 |
No explicit error classification or recovery guidance. Tools mention 'corrected here' (date range handling) and 'warns' (large_response flag) but do not document how errors are returned or what the LLM should do if pagination fails mid-stream or authentication fails.
Field filtering behavior is under-specified. 'Only these fields. Oura trims on its side, so less comes down' implies client-side is preferred, but the actual cost/benefit tradeoff (bandwidth saved vs request parsing overhead) is not documented for the LLM's reasoning.