Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,7 @@ Find files by NAME using fd with regex or glob patterns.
**Parameters:**
- `pattern` (required): Regex or glob pattern to match file names
- `path` (optional): Directory to search in (defaults to current directory)
- `limit` (optional): Maximum number of results to return (default: 0 = no limit)
- `flags` (optional): Additional flags to pass to fd

**Example:**
Expand All @@ -703,6 +704,7 @@ Fuzzy search for files by NAME using fzf's fuzzy matching.
- `pattern` (optional): Initial pattern for fd to pre-filter
- `path` (optional): Directory to search in
- `first` (optional): Return only the best match
- `limit` (optional): Maximum number of results to return (default: 0 = no limit)
- `fd_flags` (optional): Extra flags for fd
- `fzf_flags` (optional): Extra flags for fzf
- `multiline` (optional): When true, searches file CONTENTS instead of names (default: false)
Expand Down
13 changes: 12 additions & 1 deletion mcp_fd_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ def _suggest_fuzzy_terms(regex_pattern: str) -> str:
"Args:\n"
" pattern (str): Regex or glob pattern to match filenames. Required.\n"
" path (str, optional): Directory to search in. Defaults to current dir.\n"
" limit (int, optional): Maximum number of results to return. Default 0 (no limit).\n"
" flags (str, optional): Extra flags for fd (e.g., '--hidden' for hidden files).\n\n"
"Examples:\n"
" pattern='\\.py$' - Find all Python files\n"
Expand All @@ -210,6 +211,7 @@ def _suggest_fuzzy_terms(regex_pattern: str) -> str:
def search_files(
pattern: str,
path: str = ".",
limit: int = 0,
flags: str = "",
) -> dict[str, Any]:
"""Return every file or directory matching *pattern* according to fd."""
Expand All @@ -226,6 +228,8 @@ def search_files(
try:
out = subprocess.check_output(cmd, text=True, stderr=subprocess.STDOUT)
matches = [_normalize_path(p) for p in out.splitlines() if p]
if limit > 0:
matches = matches[:limit]
return {"matches": matches}
except subprocess.CalledProcessError as exc:
return {"error": exc.output.strip() or str(exc)}
Expand All @@ -247,6 +251,7 @@ def search_files(
" pattern (str, optional): Pre-filter with fd pattern (empty = all files).\n"
" path (str, optional): Directory to search. Defaults to current dir.\n"
" first (bool, optional): Return only the best match. Default false.\n"
" limit (int, optional): Maximum number of results to return. Default 0 (no limit).\n"
" fd_flags (str, optional): Extra flags for fd.\n"
" fzf_flags (str, optional): Extra flags for fzf.\n"
" multiline (bool, optional): Search file CONTENTS (not just names). Default false.\n\n"
Expand Down Expand Up @@ -283,6 +288,7 @@ def filter_files(
pattern: str = "",
path: str = ".",
first: bool = False,
limit: int = 0,
fd_flags: str = "",
fzf_flags: str = "",
multiline: bool = False,
Expand Down Expand Up @@ -381,6 +387,8 @@ def filter_files(

if first and matches:
matches = matches[:1]
elif limit > 0 and matches:
matches = matches[:limit]

result = {"matches": matches}
if warnings:
Expand All @@ -405,6 +413,7 @@ def _cli() -> None:
p_search = sub.add_parser("search", help="fd search")
p_search.add_argument("pattern")
p_search.add_argument("path", nargs="?", default=".")
p_search.add_argument("--limit", type=int, default=0, help="Maximum results")
p_search.add_argument("--flags", default="")

# filter_files sub‑command
Expand All @@ -415,6 +424,7 @@ def _cli() -> None:
p_filter.add_argument("pattern", nargs="?", default="")
p_filter.add_argument("path", nargs="?", default=".")
p_filter.add_argument("--first", action="store_true")
p_filter.add_argument("--limit", type=int, default=0, help="Maximum results")
p_filter.add_argument("--fd-flags", default="")
p_filter.add_argument("--fzf-flags", default="")
p_filter.add_argument(
Expand All @@ -424,13 +434,14 @@ def _cli() -> None:
ns = parser.parse_args()

if ns.cmd == "search":
res = search_files(ns.pattern, ns.path, ns.flags)
res = search_files(ns.pattern, ns.path, ns.limit, ns.flags)
else:
res = filter_files(
ns.filter,
ns.pattern,
ns.path,
ns.first,
ns.limit,
ns.fd_flags,
ns.fzf_flags,
ns.multiline,
Expand Down
8 changes: 4 additions & 4 deletions tests/test_fd_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -609,10 +609,10 @@ def test_multiline_cli_support():
# Verify multiline=True was passed as a positional argument
mock_filter.assert_called_once()
call_args = mock_filter.call_args
# The function signature is filter_files(filter, pattern, path, first, fd_flags, fzf_flags, multiline)
# So multiline should be the 7th argument (index 6)
if len(call_args[0]) > 6:
assert call_args[0][6] is True # positional argument
# The function signature is filter_files(filter, pattern, path, first, limit, fd_flags, fzf_flags, multiline)
# So multiline should be the 8th argument (index 7)
if len(call_args[0]) > 7:
assert call_args[0][7] is True # positional argument
else:
# Check if it was passed as keyword argument
assert call_args[1].get("multiline") is True
Expand Down
Loading