reposition_dashboard_cards
Rearrange dashboard layout by updating positions and sizes of multiple cards in a single atomic request. Specify dashcard IDs and optionally set column, row, width, or height; omitted fields keep current values.
Instructions
Reposition and/or resize multiple cards on a dashboard in a single update.
Use this to rearrange a dashboard layout atomically. Any dashcards not
included in positions keep their current layout.
Args:
dashboard_id: The ID of the dashboard.
positions: A list of layout updates. Each entry must include dashcard_id
and may include any of col, row, size_x, size_y. Omitted
fields on an entry keep their current values.
Returns: The updated dashboard object.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| dashboard_id | Yes | ||
| positions | Yes |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- server.py:1741-1818 (handler)The `reposition_dashboard_cards` tool handler function that repositions/resizes multiple cards on a dashboard atomically by fetching the current dashboard state, updating positions for specified dashcards, and PUTing the full dashcards array back.
async def reposition_dashboard_cards( dashboard_id: int, positions: list[dict[str, Any]], ctx: Context, ) -> dict[str, Any]: """ Reposition and/or resize multiple cards on a dashboard in a single update. Use this to rearrange a dashboard layout atomically. Any dashcards not included in `positions` keep their current layout. Args: dashboard_id: The ID of the dashboard. positions: A list of layout updates. Each entry must include `dashcard_id` and may include any of `col`, `row`, `size_x`, `size_y`. Omitted fields on an entry keep their current values. Returns: The updated dashboard object. """ if not positions: raise ToolError("`positions` must contain at least one entry.") updates_by_id: dict[int, dict[str, Any]] = {} for idx, entry in enumerate(positions): dc_id = entry.get("dashcard_id") if dc_id is None: raise ToolError(f"positions[{idx}] is missing required field 'dashcard_id'.") updates_by_id[int(dc_id)] = entry try: await ctx.info( f"Repositioning {len(updates_by_id)} cards on dashboard {dashboard_id}" ) dashboard = await metabase_client.request("GET", f"/dashboard/{dashboard_id}") existing_dashcards = dashboard.get("dashcards", dashboard.get("ordered_cards", [])) existing_ids = {dc.get("id") for dc in existing_dashcards} unknown = [dc_id for dc_id in updates_by_id if dc_id not in existing_ids] if unknown: raise ToolError( f"Dashcard(s) {unknown} not found on dashboard {dashboard_id}." ) dashcards = [] for dc in existing_dashcards: entry = { "id": dc["id"], "card_id": dc.get("card_id"), "row": dc.get("row"), "col": dc.get("col"), "size_x": dc.get("size_x"), "size_y": dc.get("size_y"), "parameter_mappings": list(dc.get("parameter_mappings") or []), "visualization_settings": dc.get("visualization_settings") or {}, "inline_parameters": list(dc.get("inline_parameters") or []), } update = updates_by_id.get(dc.get("id")) if update: for field in ("col", "row", "size_x", "size_y"): if update.get(field) is not None: entry[field] = update[field] dashcards.append(entry) result = await metabase_client.request( "PUT", f"/dashboard/{dashboard_id}", json={"dashcards": dashcards} ) await ctx.info( f"Successfully repositioned {len(updates_by_id)} cards on dashboard {dashboard_id}" ) return result except ToolError: raise except Exception as e: error_msg = f"Error repositioning cards on dashboard {dashboard_id}: {e}" await ctx.error(error_msg) raise ToolError(error_msg) from e - server.py:1740-1740 (registration)The `@mcp.tool` decorator that registers `reposition_dashboard_cards` as a tool with the FastMCP server.
@mcp.tool