Skip to main content
Glama

list_workouts

Retrieve a paginated list of your workout summaries in reverse-chronological order. Use this to review recent training sessions before requesting detailed set-by-set data.

Instructions

List the user's workouts in reverse-chronological order.

Use this first when the user asks about "recent workouts", "last N sessions", "what did I train on Monday", etc. Each item is a summary; call get_workout(workout_id) for full set-by-set detail when the user asks about specific weights, RPE, or progression.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
pageNo1-indexed page number.
page_sizeNoWorkouts per page. Hevy caps this at 10.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • The list_workouts tool handler function. It fetches workouts from the Hevy API with pagination, formats them into readable text, and returns the result. Registered via @mcp.tool() decorator inside the register() function.
    async def list_workouts(
        page: int = Field(1, ge=1, description="1-indexed page number."),
        page_size: int = Field(10, ge=1, le=WORKOUT_PAGE_SIZE_MAX,
                                description="Workouts per page. Hevy caps this at 10."),
    ) -> dict[str, Any]:
        """List the user's workouts in reverse-chronological order.
    
        Use this first when the user asks about "recent workouts", "last N sessions",
        "what did I train on Monday", etc. Each item is a *summary*; call
        `get_workout(workout_id)` for full set-by-set detail when the user asks
        about specific weights, RPE, or progression.
        """
        data = await client.get("/workouts", params={"page": page, "pageSize": page_size})
        items = _items(data)
        return {
            "text": "\n\n".join(format_workout(w) for w in items) or "(no workouts on this page)",
            "data": data,
            "page": page,
            "page_count": data.get("page_count") if isinstance(data, dict) else None,
        }
  • Registration entry point: register_all() calls workouts.register(mcp, ctx) which registers list_workouts (and other workout tools) onto the MCP server.
    def register_all(mcp, ctx) -> None:
        workouts.register(mcp, ctx)
  • The format_workout helper used by list_workouts to convert workout JSON into human-readable text (title, exercises, sets).
    def format_workout(w: dict[str, Any]) -> str:
        title = w.get("title") or "(untitled)"
        start = w.get("start_time") or ""
        lines = [f"# {title}  {start}".rstrip()]
        if w.get("description"):
            lines.append(w["description"])
        for ex in w.get("exercises") or []:
            ex_title = ex.get("title") or ex.get("exercise_template_id") or "exercise"
            sets = ex.get("sets") or []
            set_strs = [_fmt_set(s) for s in sets]
            lines.append(f"- {ex_title}: " + ", ".join(set_strs) if set_strs else f"- {ex_title}")
            if ex.get("notes"):
                lines.append(f"    note: {ex['notes']}")
        return "\n".join(lines)
  • The _items helper extracts the list of workout items from the API response, trying multiple possible keys (workouts, items, results, data).
    def _items(data: Any) -> list[dict[str, Any]]:
        if isinstance(data, dict):
            for k in ("workouts", "items", "results", "data"):
                v = data.get(k)
                if isinstance(v, list):
                    return v
        if isinstance(data, list):
            return data
        return []
    
    
    def _unwrap(data: Any, key: str) -> dict[str, Any]:
        if isinstance(data, dict) and key in data and isinstance(data[key], dict):
            return data[key]
        return data if isinstance(data, dict) else {}
  • The Workout Pydantic schema class used for input validation in create_workout and update_workout (not directly used by list_workouts, but part of the workout tool family).
    class Workout(_Base):
        id: str | None = None
        title: str
        description: str | None = None
        start_time: datetime | None = None
        end_time: datetime | None = None
        is_private: bool = False
        exercises: list[WorkoutExercise] = Field(default_factory=list)
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Without annotations, the description reveals reverse-chronological order and that items are summaries. It could mention pagination behavior explicitly, but the schema covers page/page_size. No contradictions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two concise sentences in the first paragraph, then usage guidance. No redundant words. Very efficient.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a paginated list tool with output schema, the description covers purpose, usage context, and behavioral trait. No gaps given the tool's simplicity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and parameters are well-documented there. The description does not add parameter details, which is acceptable given schema completeness.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool lists workouts in reverse-chronological order and specifies it provides summaries. It distinguishes from sibling tool get_workout which is for full detail.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly advises to use this tool first for recent workouts and last sessions, and provides an alternative (get_workout) for specific weights or RPE. This gives clear when-to-use and when-not-to-use guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Vellarasan/hevy-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server