Skip to content

Layer Management

Functions for creating, modifying, and organizing layers in the napari viewer.

list_layers

MCP Tool Interface

Return a list of layers with key properties.

Source code in src/napari_mcp/server.py
async def list_layers() -> list[dict[str, Any]]:
    """Return a list of layers with key properties."""
    return await NapariMCPTools.list_layers()

Implementation

Return a list of layers with key properties.

Source code in src/napari_mcp/server.py
@staticmethod
async def list_layers() -> list[dict[str, Any]]:
    """Return a list of layers with key properties."""
    # Try to proxy to external viewer first
    proxy_result = await _proxy_to_external("list_layers")
    if proxy_result is not None:
        # Ensure the result is the expected list format
        if isinstance(proxy_result, list):
            return proxy_result
        elif isinstance(proxy_result, dict) and "content" in proxy_result:
            content = proxy_result["content"]
            if isinstance(content, list):
                return content
        return []

    # Local execution
    async with _viewer_lock:

        def _build():
            v = _ensure_viewer()
            result: list[dict[str, Any]] = []  # type: ignore
            for lyr in v.layers:
                entry = {
                    "name": lyr.name,
                    "type": lyr.__class__.__name__,
                    "visible": _parse_bool(getattr(lyr, "visible", True)),
                    "opacity": float(getattr(lyr, "opacity", 1.0)),
                    "blending": getattr(lyr, "blending", None),
                }
                if (
                    hasattr(lyr, "colormap")
                    and getattr(lyr, "colormap", None) is not None
                ):
                    entry["colormap"] = getattr(lyr.colormap, "name", None) or str(
                        lyr.colormap
                    )
                if (
                    hasattr(lyr, "contrast_limits")
                    and getattr(lyr, "contrast_limits", None) is not None
                ):
                    try:
                        cl = list(lyr.contrast_limits)
                        entry["contrast_limits"] = [float(cl[0]), float(cl[1])]
                    except Exception:
                        pass
                result.append(entry)
            return result

        return _gui_execute(_build)

add_image

MCP Tool Interface

Add an image layer from a file path.

Parameters:

Name Type Description Default
path str

Path to an image readable by imageio (e.g., PNG, TIFF, OME-TIFF).

required
name str

Layer name. If None, uses filename.

None
colormap str

Napari colormap name (e.g., 'gray', 'magma').

None
blending str

Blending mode (e.g., 'translucent').

None
channel_axis int

If provided, interpret that axis as channels.

None

Returns:

Type Description
dict

Dictionary containing status, layer name, and image shape.

Source code in src/napari_mcp/server.py
async def add_image(
    path: str,
    name: str | None = None,
    colormap: str | None = None,
    blending: str | None = None,
    channel_axis: int | str | None = None,
) -> dict[str, Any]:
    """
    Add an image layer from a file path.

    Parameters
    ----------
    path : str
        Path to an image readable by imageio (e.g., PNG, TIFF, OME-TIFF).
    name : str, optional
        Layer name. If None, uses filename.
    colormap : str, optional
        Napari colormap name (e.g., 'gray', 'magma').
    blending : str, optional
        Blending mode (e.g., 'translucent').
    channel_axis : int, optional
        If provided, interpret that axis as channels.

    Returns
    -------
    dict
        Dictionary containing status, layer name, and image shape.
    """
    return await NapariMCPTools.add_image(
        path=path,
        name=name,
        colormap=colormap,
        blending=blending,
        channel_axis=channel_axis,
    )

Implementation

Add an image layer from a file path.

Parameters:

Name Type Description Default
path str

Path to an image readable by imageio (e.g., PNG, TIFF, OME-TIFF).

required
name str

Layer name. If None, uses filename.

None
colormap str

Napari colormap name (e.g., 'gray', 'magma').

None
blending str

Blending mode (e.g., 'translucent').

None
channel_axis int

If provided, interpret that axis as channels.

None

Returns:

Type Description
dict

Dictionary containing status, layer name, and image shape.

Source code in src/napari_mcp/server.py
@staticmethod
async def add_image(
    path: str,
    name: str | None = None,
    colormap: str | None = None,
    blending: str | None = None,
    channel_axis: int | str | None = None,
) -> dict[str, Any]:
    """
    Add an image layer from a file path.

    Parameters
    ----------
    path : str
        Path to an image readable by imageio (e.g., PNG, TIFF, OME-TIFF).
    name : str, optional
        Layer name. If None, uses filename.
    colormap : str, optional
        Napari colormap name (e.g., 'gray', 'magma').
    blending : str, optional
        Blending mode (e.g., 'translucent').
    channel_axis : int, optional
        If provided, interpret that axis as channels.

    Returns
    -------
    dict
        Dictionary containing status, layer name, and image shape.
    """
    # Try to proxy to external viewer first
    params: dict[str, Any] = {"path": path}
    if name:
        params["name"] = name
    if colormap:
        params["colormap"] = colormap
    if blending:
        params["blending"] = blending
    if channel_axis is not None:
        params["channel_axis"] = int(channel_axis)

    result = await _proxy_to_external("add_image", params)
    if result is not None:
        return result

    # Local execution
    import imageio.v3 as iio

    async with _viewer_lock:
        data = iio.imread(path)

        def _add():
            v = _ensure_viewer()
            layer = v.add_image(
                data,
                name=name,
                colormap=colormap,
                blending=blending,
                channel_axis=channel_axis,
            )
            _process_events()
            return {
                "status": "ok",
                "name": layer.name,
                "shape": list(np.shape(data)),
            }

        return _gui_execute(_add)

add_labels

MCP Tool Interface

Add a labels layer from a file path (e.g., PNG/TIFF with integer labels).

Source code in src/napari_mcp/server.py
async def add_labels(path: str, name: str | None = None) -> dict[str, Any]:
    """Add a labels layer from a file path (e.g., PNG/TIFF with integer labels)."""
    return await NapariMCPTools.add_labels(path=path, name=name)

Implementation

Add a labels layer from a file path (e.g., PNG/TIFF with integer labels).

Source code in src/napari_mcp/server.py
@staticmethod
async def add_labels(path: str, name: str | None = None) -> dict[str, Any]:
    """Add a labels layer from a file path (e.g., PNG/TIFF with integer labels)."""
    import imageio.v3 as iio

    async with _viewer_lock:
        try:
            from pathlib import Path

            def _add():
                v = _ensure_viewer()
                p = Path(path).expanduser().resolve(strict=False)
                data = iio.imread(str(p))
                layer = v.add_labels(data, name=name)
                _process_events()
                return {
                    "status": "ok",
                    "name": layer.name,
                    "shape": list(np.shape(data)),
                }

            return _gui_execute(_add)
        except Exception as e:
            return {
                "status": "error",
                "message": f"Failed to add labels from '{path}': {e}",
            }

add_points

MCP Tool Interface

Add a points layer.

  • points: List of [y, x] or [z, y, x] coordinates
  • name: Optional layer name
  • size: Point size in pixels
Source code in src/napari_mcp/server.py
async def add_points(
    points: list[list[float]], name: str | None = None, size: float | str = 10.0
) -> dict[str, Any]:
    """
    Add a points layer.

    - points: List of [y, x] or [z, y, x] coordinates
    - name: Optional layer name
    - size: Point size in pixels
    """
    return await NapariMCPTools.add_points(points=points, name=name, size=size)

Implementation

Add a points layer.

  • points: List of [y, x] or [z, y, x] coordinates
  • name: Optional layer name
  • size: Point size in pixels
Source code in src/napari_mcp/server.py
@staticmethod
async def add_points(
    points: list[list[float]], name: str | None = None, size: float | str = 10.0
) -> dict[str, Any]:
    """
    Add a points layer.

    - points: List of [y, x] or [z, y, x] coordinates
    - name: Optional layer name
    - size: Point size in pixels
    """
    async with _viewer_lock:

        def _add():
            v = _ensure_viewer()
            arr = np.asarray(points, dtype=float)
            layer = v.add_points(arr, name=name, size=float(size))
            _process_events()
            return {
                "status": "ok",
                "name": layer.name,
                "n_points": int(arr.shape[0]),
            }

        return _gui_execute(_add)

remove_layer

MCP Tool Interface

Remove a layer by name.

Source code in src/napari_mcp/server.py
async def remove_layer(name: str) -> dict[str, Any]:
    """Remove a layer by name."""
    return await NapariMCPTools.remove_layer(name)

Implementation

Remove a layer by name.

Source code in src/napari_mcp/server.py
@staticmethod
async def remove_layer(name: str) -> dict[str, Any]:
    """Remove a layer by name."""
    async with _viewer_lock:

        def _remove():
            v = _ensure_viewer()
            if name in v.layers:
                v.layers.remove(name)
                _process_events()
                return {"status": "removed", "name": name}
            return {"status": "not_found", "name": name}

        return _gui_execute(_remove)

set_layer_properties

MCP Tool Interface

Set common properties on a layer by name.

Source code in src/napari_mcp/server.py
async def set_layer_properties(
    name: str,
    visible: bool | None = None,
    opacity: float | None = None,
    colormap: str | None = None,
    blending: str | None = None,
    contrast_limits: list[float] | None = None,
    gamma: float | str | None = None,
    new_name: str | None = None,
) -> dict[str, Any]:
    """Set common properties on a layer by name."""
    return await NapariMCPTools.set_layer_properties(
        name=name,
        visible=visible,
        opacity=opacity,
        colormap=colormap,
        blending=blending,
        contrast_limits=contrast_limits,
        gamma=gamma,
        new_name=new_name,
    )

Implementation

Set common properties on a layer by name.

Source code in src/napari_mcp/server.py
@staticmethod
async def set_layer_properties(
    name: str,
    visible: bool | None = None,
    opacity: float | None = None,
    colormap: str | None = None,
    blending: str | None = None,
    contrast_limits: list[float] | None = None,
    gamma: float | str | None = None,
    new_name: str | None = None,
) -> dict[str, Any]:
    """Set common properties on a layer by name."""
    async with _viewer_lock:

        def _set():
            v = _ensure_viewer()
            if name not in v.layers:
                return {"status": "not_found", "name": name}
            lyr = v.layers[name]
            if visible is not None and hasattr(lyr, "visible"):
                lyr.visible = _parse_bool(visible)
            if opacity is not None and hasattr(lyr, "opacity"):
                lyr.opacity = float(opacity)
            if colormap is not None and hasattr(lyr, "colormap"):
                lyr.colormap = colormap
            if blending is not None and hasattr(lyr, "blending"):
                lyr.blending = blending
            if contrast_limits is not None and hasattr(lyr, "contrast_limits"):
                with contextlib.suppress(Exception):
                    lyr.contrast_limits = [
                        float(contrast_limits[0]),
                        float(contrast_limits[1]),
                    ]
            if gamma is not None and hasattr(lyr, "gamma"):
                lyr.gamma = float(gamma)
            if new_name is not None:
                lyr.name = new_name
            _process_events()
            return {"status": "ok", "name": lyr.name}

        return _gui_execute(_set)

reorder_layer

MCP Tool Interface

Reorder a layer by name.

Provide exactly one of: - index: absolute target index - before: move before this layer name - after: move after this layer name

Source code in src/napari_mcp/server.py
async def reorder_layer(
    name: str,
    index: int | str | None = None,
    before: str | None = None,
    after: str | None = None,
) -> dict[str, Any]:
    """
    Reorder a layer by name.

    Provide exactly one of:
    - index: absolute target index
    - before: move before this layer name
    - after: move after this layer name
    """
    return await NapariMCPTools.reorder_layer(
        name=name, index=index, before=before, after=after
    )

Implementation

Reorder a layer by name.

Provide exactly one of: - index: absolute target index - before: move before this layer name - after: move after this layer name

Source code in src/napari_mcp/server.py
@staticmethod
async def reorder_layer(
    name: str,
    index: int | str | None = None,
    before: str | None = None,
    after: str | None = None,
) -> dict[str, Any]:
    """
    Reorder a layer by name.

    Provide exactly one of:
    - index: absolute target index
    - before: move before this layer name
    - after: move after this layer name
    """
    async with _viewer_lock:

        def _reorder():
            v = _ensure_viewer()
            if name not in v.layers:
                return {"status": "not_found", "name": name}
            if sum(x is not None for x in (index, before, after)) != 1:
                return {
                    "status": "error",
                    "message": "Provide exactly one of index, before, or after",
                }
            cur = v.layers.index(name)
            target = cur
            if index is not None:
                target = max(0, min(int(index), len(v.layers) - 1))
            elif before is not None:
                if before not in v.layers:
                    return {"status": "not_found", "name": before}
                target = v.layers.index(before)
            elif after is not None:
                if after not in v.layers:
                    return {"status": "not_found", "name": after}
                target = v.layers.index(after) + 1
            if target != cur:
                v.layers.move(cur, target)
            _process_events()
            return {"status": "ok", "name": name, "index": v.layers.index(name)}

        return _gui_execute(_reorder)

set_active_layer

MCP Tool Interface

Set the selected/active layer by name.

Source code in src/napari_mcp/server.py
async def set_active_layer(name: str) -> dict[str, Any]:
    """Set the selected/active layer by name."""
    return await NapariMCPTools.set_active_layer(name)

Implementation

Set the selected/active layer by name.

Source code in src/napari_mcp/server.py
@staticmethod
async def set_active_layer(name: str) -> dict[str, Any]:
    """Set the selected/active layer by name."""
    async with _viewer_lock:

        def _set_active():
            v = _ensure_viewer()
            if name not in v.layers:
                return {"status": "not_found", "name": name}
            v.layers.selection = {v.layers[name]}
            _process_events()
            return {"status": "ok", "active": name}

        return _gui_execute(_set_active)