Skip to content

Storage Tools

storage

Storage and hardware tools.

list_block_devices async

list_block_devices(host: Host = None) -> str

List block devices.

Retrieves all block devices (disks, partitions, LVM volumes) with their name, size, type, mount point, and filesystem information.

Source code in src/linux_mcp_server/tools/storage.py
@mcp.tool(
    title="List block devices",
    description="List block devices on the system",
    annotations=ToolAnnotations(readOnlyHint=True),
)
@log_tool_call
@disallow_local_execution_in_containers
async def list_block_devices(
    host: Host = None,
) -> str:
    """List block devices.

    Retrieves all block devices (disks, partitions, LVM volumes) with their
    name, size, type, mount point, and filesystem information.
    """
    try:
        cmd = get_command("list_block_devices")
        returncode, stdout, _ = await cmd.run(host=host)

        if is_successful_output(returncode, stdout):
            return format_block_devices(stdout)

        # Fallback message if lsblk fails
        return "Error: Unable to list block devices. lsblk command may not be available."
    except FileNotFoundError:
        return "Error: lsblk command not found."
    except Exception as e:
        return f"Error listing block devices: {str(e)}"

list_directories async

list_directories(
    path: Annotated[str, "The directory path to analyze"],
    order_by: Annotated[
        OrderBy,
        "Sort order - 'size', 'name', or 'modified' (default: 'name')",
    ] = OrderBy.NAME,
    sort: Annotated[
        SortBy,
        "Sort direction - 'ascending' or 'descending' (default: 'ascending')",
    ] = SortBy.ASCENDING,
    top_n: Annotated[
        int | None,
        Field(
            description="Optional limit on number of directories to return (1-1000, only used with size ordering)",
            gt=0,
            le=1000,
        ),
    ] = None,
    host: Host = None,
) -> str

List directories under a specified path.

Retrieves subdirectories with their size (when ordered by size) or modification time, supporting flexible sorting and result limiting.

Source code in src/linux_mcp_server/tools/storage.py
@mcp.tool(
    title="List directories",
    description="List directories under a specified path with various sorting options.",
    annotations=ToolAnnotations(readOnlyHint=True),
)
@log_tool_call
@disallow_local_execution_in_containers
async def list_directories(
    path: t.Annotated[str, "The directory path to analyze"],
    order_by: t.Annotated[OrderBy, "Sort order - 'size', 'name', or 'modified' (default: 'name')"] = OrderBy.NAME,
    sort: t.Annotated[SortBy, "Sort direction - 'ascending' or 'descending' (default: 'ascending')"] = SortBy.ASCENDING,
    top_n: t.Annotated[
        int | None,
        Field(
            description="Optional limit on number of directories to return (1-1000, only used with size ordering)",
            gt=0,
            le=1_000,
        ),
    ] = None,
    host: Host = None,
) -> str:
    """List directories under a specified path.

    Retrieves subdirectories with their size (when ordered by size) or
    modification time, supporting flexible sorting and result limiting.
    """
    path = _validate_path(path)

    # Get the appropriate command for the order_by field
    cmd_name = DIRECTORY_COMMANDS[order_by]
    cmd = get_command(cmd_name)

    try:
        returncode, stdout, stderr = await cmd.run(host=host, path=path)

        if returncode != 0:
            raise ToolError(f"Error running command: command failed with return code {returncode}: {stderr}")

        # Parse the output
        entries = parse_directory_listing(stdout, order_by)

        # Apply top_n limit if specified
        if top_n:
            # Sort first if we need to limit
            if order_by == OrderBy.SIZE:
                entries = sorted(entries, key=lambda e: e.size, reverse=sort == SortBy.DESCENDING)
            elif order_by == OrderBy.MODIFIED:
                entries = sorted(entries, key=lambda e: e.modified, reverse=sort == SortBy.DESCENDING)
            else:
                entries = sorted(entries, key=lambda e: e.name.lower(), reverse=sort == SortBy.DESCENDING)
            entries = entries[:top_n]

        # Format the output
        return format_directory_listing(entries, path, order_by, reverse=sort == SortBy.DESCENDING)

    except Exception as e:
        raise ToolError(f"Error listing directories: {str(e)}") from e

list_files async

list_files(
    path: Annotated[str, "The path to analyze"],
    order_by: Annotated[
        OrderBy,
        "Sort order - 'size', 'name', or 'modified' (default: 'name')",
    ] = OrderBy.NAME,
    sort: Annotated[
        SortBy,
        "Sort direction - 'ascending' or 'descending' (default: 'ascending')",
    ] = SortBy.ASCENDING,
    top_n: Annotated[
        int | None,
        Field(
            description="Optional limit on number of files to return (1-1000, only used with size ordering)",
            gt=0,
            le=1000,
        ),
    ] = None,
    host: Host = None,
) -> str

List files under a specified path.

Retrieves files with their size or modification time, supporting flexible sorting and result limiting. Useful for finding large or recently modified files.

Source code in src/linux_mcp_server/tools/storage.py
@mcp.tool(
    title="List files",
    description="List files under a specified path with various sorting options.",
    annotations=ToolAnnotations(readOnlyHint=True),
)
@log_tool_call
@disallow_local_execution_in_containers
async def list_files(
    path: t.Annotated[str, "The path to analyze"],
    order_by: t.Annotated[OrderBy, "Sort order - 'size', 'name', or 'modified' (default: 'name')"] = OrderBy.NAME,
    sort: t.Annotated[SortBy, "Sort direction - 'ascending' or 'descending' (default: 'ascending')"] = SortBy.ASCENDING,
    top_n: t.Annotated[
        int | None,
        Field(
            description="Optional limit on number of files to return (1-1000, only used with size ordering)",
            gt=0,
            le=1_000,
        ),
    ] = None,
    host: Host = None,
) -> str:
    """List files under a specified path.

    Retrieves files with their size or modification time, supporting flexible
    sorting and result limiting. Useful for finding large or recently modified files.
    """
    # For local execution, validate path
    if not host:
        path = _validate_path(path)

    # Get the appropriate command for the order_by field
    cmd_name = FILE_COMMANDS[order_by]
    cmd = get_command(cmd_name)

    try:
        returncode, stdout, stderr = await cmd.run(host=host, path=path)

        if returncode != 0:
            raise ToolError(f"Error running command: command failed with return code {returncode}: {stderr}")

        # Parse the output
        entries = parse_file_listing(stdout, order_by)

        # Apply top_n limit if specified
        if top_n:
            # Sort first if we need to limit
            if order_by == OrderBy.SIZE:
                entries = sorted(entries, key=lambda e: e.size, reverse=sort == SortBy.DESCENDING)
            elif order_by == OrderBy.MODIFIED:
                entries = sorted(entries, key=lambda e: e.modified, reverse=sort == SortBy.DESCENDING)
            else:
                entries = sorted(entries, key=lambda e: e.name.lower(), reverse=sort == SortBy.DESCENDING)
            entries = entries[:top_n]

        # Format the output
        return format_file_listing(entries, path, order_by, reverse=sort == SortBy.DESCENDING)

    except Exception as e:
        raise ToolError(f"Error listing files: {str(e)}") from e

read_file async

read_file(
    path: Annotated[str, "The file path to read"],
    host: Host = None,
) -> str

Read the contents of a file.

Retrieves the full contents of a text file. The path must be absolute and the file must exist. Binary files may not display correctly.

Source code in src/linux_mcp_server/tools/storage.py
@mcp.tool(
    title="Read file",
    description="Read the contents of a file using cat",
    annotations=ToolAnnotations(readOnlyHint=True),
)
@log_tool_call
@disallow_local_execution_in_containers
async def read_file(
    path: t.Annotated[str, "The file path to read"],
    host: Host = None,
) -> str:
    """Read the contents of a file.

    Retrieves the full contents of a text file. The path must be absolute
    and the file must exist. Binary files may not display correctly.
    """

    # Validate path
    path = _validate_path(path)

    if not host:
        # For local execution, check early if file exists
        if not os.path.isfile(path):
            raise ToolError(f"Path is not a file: {path}")

    cmd = get_command("read_file")

    try:
        returncode, stdout, stderr = await cmd.run_bytes(host=host, path=path)

        if returncode != 0:
            raise ToolError(f"Error running command: command failed with return code {returncode}: {stderr}")

        return stdout.decode("utf-8")
    except Exception as e:
        raise ToolError(f"Error reading file: {str(e)}") from e