Skip to content

Read file

read_file

ReadFileTool — read file content with optional line-range support.

Registered as read_file via the axm.tools entry point.

ReadFileTool

Read file content with optional line-range support.

Returns file content with line numbers. Supports partial reads via start_line / end_line (1-indexed, inclusive). Registered as read_file via axm.tools entry point.

Source code in packages/axm-edit/src/axm_edit/tools/read_file.py
Python
class ReadFileTool:
    """Read file content with optional line-range support.

    Returns file content with line numbers. Supports partial reads
    via ``start_line`` / ``end_line`` (1-indexed, inclusive).
    Registered as ``read_file`` via axm.tools entry point.
    """

    agent_hint: str = (
        "Read file content with line numbers. Supports partial reads"
        " via start_line/end_line (1-indexed)."
        " Use for raw source when ast_inspect is insufficient."
    )

    @property
    def name(self) -> str:
        """Tool name used for MCP registration."""
        return "read_file"

    def execute(
        self,
        *,
        path: str = ".",
        file: str | None = None,
        start_line: int | None = None,
        end_line: int | None = None,
        **kwargs: object,
    ) -> ToolResult:
        """Read a file, optionally restricting to a line range.

        Args:
            path: Project root directory.
            file: Relative path to the file to read.
            start_line: Optional 1-indexed start line (inclusive).
            end_line: Optional 1-indexed end line (inclusive).

        Returns:
            ToolResult with file content, line numbers, and metadata.
        """
        root_str = path
        file_rel = file

        if not file_rel:
            return ToolResult(success=False, error="Missing required argument: file")

        # Resolve and validate file path
        result = _resolve_file(root_str, file_rel)
        if isinstance(result, ToolResult):
            return result
        resolved = result

        # Validate line range
        range_error = _validate_line_range(start_line, end_line)
        if range_error:
            return ToolResult(success=False, error=range_error)

        # Read content
        try:
            text = resolved.read_text(encoding="utf-8")
        except UnicodeDecodeError:
            return ToolResult(
                success=False,
                error=f"Cannot decode file as UTF-8: {file_rel}",
            )

        all_lines = text.splitlines(keepends=True)
        selected, first_line_num = _select_lines(all_lines, start_line, end_line)
        content = _format_numbered(selected, first_line_num)

        logger.debug("read %s: %d/%d lines", file_rel, len(selected), len(all_lines))

        return ToolResult(
            success=True,
            data={
                "content": content,
                "file": file_rel,
                "total_lines": len(all_lines),
                "showing": {
                    "start": first_line_num,
                    "end": first_line_num + len(selected) - 1,
                    "count": len(selected),
                },
            },
        )
name property

Tool name used for MCP registration.

execute(*, path='.', file=None, start_line=None, end_line=None, **kwargs)

Read a file, optionally restricting to a line range.

Parameters:

Name Type Description Default
path str

Project root directory.

'.'
file str | None

Relative path to the file to read.

None
start_line int | None

Optional 1-indexed start line (inclusive).

None
end_line int | None

Optional 1-indexed end line (inclusive).

None

Returns:

Type Description
ToolResult

ToolResult with file content, line numbers, and metadata.

Source code in packages/axm-edit/src/axm_edit/tools/read_file.py
Python
def execute(
    self,
    *,
    path: str = ".",
    file: str | None = None,
    start_line: int | None = None,
    end_line: int | None = None,
    **kwargs: object,
) -> ToolResult:
    """Read a file, optionally restricting to a line range.

    Args:
        path: Project root directory.
        file: Relative path to the file to read.
        start_line: Optional 1-indexed start line (inclusive).
        end_line: Optional 1-indexed end line (inclusive).

    Returns:
        ToolResult with file content, line numbers, and metadata.
    """
    root_str = path
    file_rel = file

    if not file_rel:
        return ToolResult(success=False, error="Missing required argument: file")

    # Resolve and validate file path
    result = _resolve_file(root_str, file_rel)
    if isinstance(result, ToolResult):
        return result
    resolved = result

    # Validate line range
    range_error = _validate_line_range(start_line, end_line)
    if range_error:
        return ToolResult(success=False, error=range_error)

    # Read content
    try:
        text = resolved.read_text(encoding="utf-8")
    except UnicodeDecodeError:
        return ToolResult(
            success=False,
            error=f"Cannot decode file as UTF-8: {file_rel}",
        )

    all_lines = text.splitlines(keepends=True)
    selected, first_line_num = _select_lines(all_lines, start_line, end_line)
    content = _format_numbered(selected, first_line_num)

    logger.debug("read %s: %d/%d lines", file_rel, len(selected), len(all_lines))

    return ToolResult(
        success=True,
        data={
            "content": content,
            "file": file_rel,
            "total_lines": len(all_lines),
            "showing": {
                "start": first_line_num,
                "end": first_line_num + len(selected) - 1,
                "count": len(selected),
            },
        },
    )