create_routine_folder
Create a new routine folder to organize your workout routines. Returns the folder ID for use when creating routines.
Instructions
Create a new routine folder. Returns the new folder including its id, which
you can pass to create_routine as folder_id.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| title | Yes |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- src/hevy_mcp/tools/folders.py:28-34 (handler)The actual handler function for create_routine_folder tool. Accepts a title string, POSTs to Hevy API /routine_folders, and returns created folder data.
async def create_routine_folder(title: str) -> dict[str, Any]: """Create a new routine folder. Returns the new folder including its id, which you can pass to `create_routine` as `folder_id`. """ data = await client.post("/routine_folders", json={"routine_folder": {"title": title}}) return {"text": f"Folder '{title}' created.", "data": data} - src/hevy_mcp/tools/__init__.py:6-13 (registration)Registering of all tool modules via register_all() which calls folders.register(mcp, ctx).
def register_all(mcp, ctx) -> None: workouts.register(mcp, ctx) routines.register(mcp, ctx) folders.register(mcp, ctx) templates.register(mcp, ctx) webhooks.register(mcp, ctx) analytics.register(mcp, ctx) - src/hevy_mcp/tools/folders.py:10-34 (registration)The register() function that attaches create_routine_folder (and other folder tools) to the MCP server via @mcp.tool() decorator.
def register(mcp, ctx) -> None: client = ctx.client @mcp.tool() @tool_guard async def list_routine_folders(page: int = 1, page_size: int = 10) -> dict[str, Any]: """List the user's routine folders (e.g. 'Push/Pull/Legs', 'Hypertrophy Block').""" return {"data": await client.get("/routine_folders", params={"page": page, "pageSize": page_size})} @mcp.tool() @tool_guard async def get_routine_folder(folder_id: int) -> dict[str, Any]: """Fetch a single routine folder by id.""" return {"data": await client.get(f"/routine_folders/{folder_id}")} @mcp.tool() @tool_guard async def create_routine_folder(title: str) -> dict[str, Any]: """Create a new routine folder. Returns the new folder including its id, which you can pass to `create_routine` as `folder_id`. """ data = await client.post("/routine_folders", json={"routine_folder": {"title": title}}) return {"text": f"Folder '{title}' created.", "data": data} - src/hevy_mcp/errors.py:47-80 (helper)The @tool_guard decorator used on create_routine_folder to handle errors uniformly.
def tool_guard(func: Callable[..., Awaitable[Any]]) -> Callable[..., Awaitable[Any]]: """Decorator: convert exceptions into `{error, hint}` and emit structured logs.""" @functools.wraps(func) async def wrapper(*args: Any, **kwargs: Any) -> Any: start = time.monotonic() name = func.__name__ try: result = await func(*args, **kwargs) log.info("tool=%s status=ok duration_ms=%.1f", name, (time.monotonic() - start) * 1000) return result except HevyApiError as e: log.warning( "tool=%s status=hevy_error http=%d duration_ms=%.1f msg=%s", name, e.status, (time.monotonic() - start) * 1000, e.message, ) return {"error": e.message, "hint": e.hint, "http_status": e.status} except httpx.TimeoutException: log.warning("tool=%s status=timeout duration_ms=%.1f", name, (time.monotonic() - start) * 1000) return { "error": "Hevy API request timed out.", "hint": "Retry the call. If it keeps timing out, reduce page_size or scope.", } except ValueError as e: log.warning("tool=%s status=bad_input duration_ms=%.1f msg=%s", name, (time.monotonic() - start) * 1000, e) return {"error": str(e), "hint": "Re-read the tool's input schema and adjust the arguments."} except Exception as e: # noqa: BLE001 — last-resort guard so Claude never sees a stack trace log.exception("tool=%s status=internal_error duration_ms=%.1f", name, (time.monotonic() - start) * 1000) return { "error": f"Unexpected internal error: {type(e).__name__}: {e}", "hint": "This is a bug in hevy-mcp. Retry once; if it persists, file an issue with the tool name and inputs.", } return wrapper - src/hevy_mcp/hevy_client.py:97-109 (helper)The HevyClient.post() and request() methods that create_routine_folder uses to make the actual API call.
# ---- convenience ---- # async def get(self, path: str, **kw: Any) -> Any: return await self.request("GET", path, **kw) async def post(self, path: str, **kw: Any) -> Any: return await self.request("POST", path, **kw) async def put(self, path: str, **kw: Any) -> Any: return await self.request("PUT", path, **kw) async def delete(self, path: str, **kw: Any) -> Any: return await self.request("DELETE", path, **kw)