From debe79e33e2f2441eeff9a2a06121130cf93a459 Mon Sep 17 00:00:00 2001 From: Lukasz Raczylo Date: Fri, 19 Jun 2026 22:19:18 +0100 Subject: [PATCH] feat(search): bound default result count and add include_hidden MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two file_search gaps: - max_results defaulted to 0 (unbounded), so a broad pattern returned every match — unbounded memory + token blowup. The configured MaxSearchResults (default 1000) existed but was dead; wire it as the builtIn default. Explicit max_results still wins, and the cursor footer pages the rest. - search.Request.IncludeHidden was a dead field with no tool param. Add an include_hidden bool (default false) so dotfiles (.github/, etc.) are searchable. --- internal/server/handlers_file.go | 20 ++++++++++++-------- internal/server/server.go | 3 +++ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/internal/server/handlers_file.go b/internal/server/handlers_file.go index 9bb08e8..4d18952 100644 --- a/internal/server/handlers_file.go +++ b/internal/server/handlers_file.go @@ -61,7 +61,10 @@ func (s *Server) handleFileSearch(ctx context.Context, request mcp.CallToolReque prefsMaxResults = prefs.DefaultMaxResults prefsCluster = prefs.DefaultCluster } - maxResults := effectiveInt(request, "max_results", prefsMaxResults, 0) + // Default to the configured cap (not 0/unbounded) so a broad pattern can't + // flood memory and the context window; an explicit max_results still wins, + // and the cursor footer lets the caller page through the rest. + maxResults := effectiveInt(request, "max_results", prefsMaxResults, s.cfg.MaxSearchResults) cluster := effectiveBool(request, "cluster", prefsCluster, false) cursorStr := request.GetString("cursor", "") @@ -97,13 +100,14 @@ func (s *Server) handleFileSearch(ctx context.Context, request mcp.CallToolReque } req := &search.Request{ - Pattern: pattern, - Paths: paths, - FileTypes: fileTypes, - IgnoreCase: ignoreCase, - Regex: regex, - ContextLines: contextLines, - MaxResults: rgMaxResults, + Pattern: pattern, + Paths: paths, + FileTypes: fileTypes, + IgnoreCase: ignoreCase, + Regex: regex, + ContextLines: contextLines, + MaxResults: rgMaxResults, + IncludeHidden: request.GetBool("include_hidden", false), } results, err := s.searcher.Search(ctx, req) diff --git a/internal/server/server.go b/internal/server/server.go index 13576da..72324dc 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -129,6 +129,9 @@ func (s *Server) registerTools() { mcp.WithBoolean("ignore_case", mcp.Description("Case insensitive search"), ), + mcp.WithBoolean("include_hidden", + mcp.Description("Search hidden files and directories (dotfiles like .github/). Default: false."), + ), mcp.WithBoolean("regex", mcp.Description("Treat pattern as regex (default: true)"), ),