Skip to main content
Glama
voducdan

metabase-mcp

by voducdan

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

TableJSON Schema
NameRequiredDescriptionDefault
dashboard_idYes
positionsYes

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • 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
Behavior5/5

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

Despite no annotations, description fully discloses atomic update behavior, that omitted fields retain current values, and return value (updated dashboard object). No conflict or missing behavioral traits.

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?

Description is brief yet comprehensive, with clear sections (overview, Args, Returns). Every sentence adds value, and critical info is front-loaded in the first two sentences.

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?

Given only two parameters, presence of output schema, and detailed description covering purpose, usage, parameters, and returns, the description is fully complete for this tool's complexity.

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

Parameters5/5

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

Input schema has 0% description coverage, but description explains both parameters in detail, including sub-fields of positions (dashcard_id, col, row, size_x, size_y) and their optionality, far exceeding schema's minimal info.

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?

Description clearly states 'Reposition and/or resize multiple cards on a dashboard in a single update', uses specific verb-resource pairing, and distinguishes from sibling tools like update_dashboard_card_position by emphasizing bulk atomic update.

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

Usage Guidelines4/5

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

Explicitly says 'Use this to rearrange a dashboard layout atomically' and describes behavior for omitted cards. Lacks direct comparison to alternative single-card tool, but context signals sibling list includes update_dashboard_card_position, aiding inference.

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/voducdan/matebase-mcp'

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