Skip to content

File Search Tools

The FileSearch tools provide file discovery and content search capabilities commonly needed in agent workflows: glob-based file finding, regex content search (grep), and directory tree display.

Class Overview

  • FileSearch - Three static methods covering the most common file-discovery operations:
    • glob() - Find files by pattern
    • grep() - Search file contents with regex
    • tree() - Display directory structure

Usage

Glob - Find Files by Pattern

from toolregistry_hub import FileSearch

# Find all Python files recursively
files = FileSearch.glob("**/*.py", root="/path/to/project")

# Non-recursive search in root only
files = FileSearch.glob("*.txt", root=".", recursive=False)

Results are sorted by modification time (most recent first), capped at 1000 results. Paths are relative to root.

Grep - Search File Contents

# Search for pattern in directory
results = FileSearch.grep("import os", path="/path/to/project")
# [{"file": "main.py", "line_number": 3, "content": "import os"}, ...]

# Search with file filter
results = FileSearch.grep(r"def\s+test_", path=".", file_pattern="*.py")

# Single file search
results = FileSearch.grep("TODO", path="src/main.py")

# Limit results
results = FileSearch.grep(".", path=".", max_results=10)

Each result is a dict with file (relative path), line_number (1-based), and content (stripped line).

Tree - Directory Structure

# Basic tree
print(FileSearch.tree("/path/to/project"))
# project/
# +-- src/
# |   +-- main.py
# |   +-- utils.py
# +-- tests/
# |   +-- test_main.py
# +-- README.md

# Limit depth and filter files
print(FileSearch.tree(".", max_depth=2, file_pattern="*.py"))

# Show hidden files
print(FileSearch.tree(".", show_hidden=True))

Parameters

glob()

Parameter Type Default Description
pattern str required Glob pattern (e.g. "**/*.py")
root str "." Root directory to search from
recursive bool True Whether ** matches subdirectories

grep()

Parameter Type Default Description
pattern str required Regex pattern to search for
path str "." File or directory to search in
recursive bool True Search subdirectories
file_pattern str \| None None Glob to filter files (e.g. "*.py")
max_results int 50 Maximum results (capped at 200)

tree()

Parameter Type Default Description
path str "." Root directory
max_depth int 3 Maximum depth to display
show_hidden bool False Show hidden files/directories
file_pattern str \| None None Glob to filter displayed files

Safety Caps

  • Glob: 1000 results max
  • Grep: 200 results max
  • Tree: 2000 entries max

MCP Server Endpoints

POST /tools/fs/file_search/glob
POST /tools/fs/file_search/grep
POST /tools/fs/file_search/tree

API Reference

toolregistry_hub.file_search.FileSearch

File and content search tools.

glob staticmethod

glob(pattern: str, root: str = '.', recursive: bool = True) -> list[str]

Find files matching a glob pattern.

Parameters:

Name Type Description Default
pattern str

Glob pattern (e.g. "**/*.py", "src/**/*.ts").

required
root str

Root directory to search from. Defaults to current directory.

'.'
recursive bool

Whether ** matches subdirectories. Defaults to True.

True

Returns:

Type Description
list[str]

List of matching file paths relative to root, sorted by

list[str]

modification time (most recent first). Capped at 1000 results.

Raises:

Type Description
FileNotFoundError

If root does not exist or is not a directory.

Source code in toolregistry_hub/file_search.py
@staticmethod
def glob(
    pattern: str,
    root: str = ".",
    recursive: bool = True,
) -> list[str]:
    """Find files matching a glob pattern.

    Args:
        pattern: Glob pattern (e.g. ``"**/*.py"``, ``"src/**/*.ts"``).
        root: Root directory to search from. Defaults to current directory.
        recursive: Whether ``**`` matches subdirectories. Defaults to True.

    Returns:
        List of matching file paths relative to *root*, sorted by
        modification time (most recent first).  Capped at 1000 results.

    Raises:
        FileNotFoundError: If *root* does not exist or is not a directory.
    """
    root_path = Path(root).resolve()
    if not root_path.is_dir():
        raise FileNotFoundError(
            f"Root is not a directory or does not exist: {root}"
        )

    if recursive:
        matches = list(root_path.glob(pattern))
    else:
        # Non-recursive: only match in the root directory itself
        matches = [p for p in root_path.glob(pattern) if p.parent == root_path]

    # Sort by modification time, most recent first
    matches.sort(key=lambda p: p.stat().st_mtime, reverse=True)

    # Cap results
    matches = matches[:_MAX_GLOB_RESULTS]

    return [str(p.relative_to(root_path)) for p in matches]

grep staticmethod

grep(pattern: str, path: str = '.', recursive: bool = True, file_pattern: str | None = None, max_results: int = 50) -> list[dict]

Search file contents using regex.

Parameters:

Name Type Description Default
pattern str

Regex pattern to search for.

required
path str

File or directory to search in. Defaults to current directory.

'.'
recursive bool

Whether to search subdirectories. Defaults to True.

True
file_pattern str | None

Optional glob to filter files (e.g. "*.py").

None
max_results int

Maximum number of match results to return. Clamped to an internal cap of 200.

50

Returns:

Type Description
list[dict]

List of dicts, each with keys:

list[dict]
  • file (str): path relative to search root
list[dict]
  • line_number (int): 1-based line number
list[dict]
  • content (str): the matching line (stripped)

Raises:

Type Description
FileNotFoundError

If path does not exist.

error

If pattern is not a valid regex.

Source code in toolregistry_hub/file_search.py
@staticmethod
def grep(
    pattern: str,
    path: str = ".",
    recursive: bool = True,
    file_pattern: str | None = None,
    max_results: int = 50,
) -> list[dict]:
    """Search file contents using regex.

    Args:
        pattern: Regex pattern to search for.
        path: File or directory to search in. Defaults to current directory.
        recursive: Whether to search subdirectories. Defaults to True.
        file_pattern: Optional glob to filter files (e.g. ``"*.py"``).
        max_results: Maximum number of match results to return.
            Clamped to an internal cap of 200.

    Returns:
        List of dicts, each with keys:

        - ``file`` (str): path relative to search root
        - ``line_number`` (int): 1-based line number
        - ``content`` (str): the matching line (stripped)

    Raises:
        FileNotFoundError: If *path* does not exist.
        re.error: If *pattern* is not a valid regex.
    """
    target = Path(path).resolve()
    if not target.exists():
        raise FileNotFoundError(f"Path does not exist: {path}")

    regex = re.compile(pattern)
    effective_max = min(max_results, _MAX_GREP_RESULTS)
    results: list[dict] = []

    if target.is_file():
        FileSearch._grep_file(target, regex, target.parent, results, effective_max)
        return results

    # Directory search
    files = target.rglob("*") if recursive else target.iterdir()

    for filepath in sorted(files):
        if len(results) >= effective_max:
            break
        if not filepath.is_file():
            continue
        if file_pattern and not fnmatch.fnmatch(filepath.name, file_pattern):
            continue
        FileSearch._grep_file(filepath, regex, target, results, effective_max)

    return results

tree staticmethod

tree(path: str = '.', max_depth: int = 3, show_hidden: bool = False, file_pattern: str | None = None) -> str

Display directory tree structure.

Parameters:

Name Type Description Default
path str

Root directory. Defaults to current directory.

'.'
max_depth int

Maximum depth to display. Defaults to 3.

3
show_hidden bool

Whether to show hidden files/directories.

False
file_pattern str | None

Optional glob to filter displayed files.

None

Returns:

Type Description
str

Tree-formatted string representation of the directory.

Raises:

Type Description
FileNotFoundError

If path does not exist or is not a directory.

ValueError

If max_depth is less than 1.

Source code in toolregistry_hub/file_search.py
@staticmethod
def tree(
    path: str = ".",
    max_depth: int = 3,
    show_hidden: bool = False,
    file_pattern: str | None = None,
) -> str:
    """Display directory tree structure.

    Args:
        path: Root directory. Defaults to current directory.
        max_depth: Maximum depth to display. Defaults to 3.
        show_hidden: Whether to show hidden files/directories.
        file_pattern: Optional glob to filter displayed files.

    Returns:
        Tree-formatted string representation of the directory.

    Raises:
        FileNotFoundError: If *path* does not exist or is not a directory.
        ValueError: If *max_depth* is less than 1.
    """
    root = Path(path).resolve()
    if not root.is_dir():
        raise FileNotFoundError(
            f"Path is not a directory or does not exist: {path}"
        )
    if max_depth < 1:
        raise ValueError("max_depth must be 1 or greater.")

    lines: list[str] = [root.name + "/"]
    count = [0]  # mutable counter for the nested function

    FileSearch._build_tree(
        root, "", max_depth, 1, show_hidden, file_pattern, lines, count
    )

    if count[0] >= _MAX_TREE_ENTRIES:
        lines.append(f"\n... truncated at {_MAX_TREE_ENTRIES} entries")

    return "\n".join(lines)