From a67c64fe12d907cdf7d1d78e9a1dc26a70e8de9c Mon Sep 17 00:00:00 2001 From: Jochen Date: Fri, 16 May 2025 13:57:21 +0200 Subject: [PATCH] feat(search_files): support glob pattern --- filesystemserver/handler.go | 5 ++- filesystemserver/handler_test.go | 65 ++++++++++++++++++++++++++++++++ go.mod | 1 + go.sum | 2 + 4 files changed, 71 insertions(+), 2 deletions(-) diff --git a/filesystemserver/handler.go b/filesystemserver/handler.go index c7e6a04..b9ad465 100644 --- a/filesystemserver/handler.go +++ b/filesystemserver/handler.go @@ -13,6 +13,7 @@ import ( "time" "github.com/gabriel-vasile/mimetype" + "github.com/gobwas/glob" "github.com/mark3labs/mcp-go/mcp" "slices" ) @@ -252,7 +253,7 @@ func (fs *FilesystemHandler) searchFiles( rootPath, pattern string, ) ([]string, error) { var results []string - pattern = strings.ToLower(pattern) + globPattern := glob.MustCompile(pattern) err := filepath.Walk( rootPath, @@ -266,7 +267,7 @@ func (fs *FilesystemHandler) searchFiles( return nil // Skip invalid paths } - if strings.Contains(strings.ToLower(info.Name()), pattern) { + if globPattern.Match(info.Name()) { results = append(results, path) } return nil diff --git a/filesystemserver/handler_test.go b/filesystemserver/handler_test.go index 6ffd3c3..9119303 100644 --- a/filesystemserver/handler_test.go +++ b/filesystemserver/handler_test.go @@ -68,3 +68,68 @@ func TestReadfile_NoAccess(t *testing.T) { assert.True(t, result.IsError) assert.Contains(t, fmt.Sprint(result.Content[0]), "access denied - path outside allowed directories") } + +func TestSearchFiles_Pattern(t *testing.T) { + + // setting up test folder + // tmpDir/ + // - foo/ + // - bar.h + // - test.c + // - test.h + // - test.c + + dir := t.TempDir() + test_h := filepath.Join(dir, "test.h") + err := os.WriteFile(test_h, []byte("foo"), 0644) + require.NoError(t, err) + + test_c := filepath.Join(dir, "test.c") + err = os.WriteFile(test_c, []byte("foo"), 0644) + require.NoError(t, err) + + fooDir := filepath.Join(dir, "foo") + err = os.MkdirAll(fooDir, 0755) + require.NoError(t, err) + + foo_bar_h := filepath.Join(fooDir, "bar.h") + err = os.WriteFile(foo_bar_h, []byte("foo"), 0644) + require.NoError(t, err) + + foo_test_c := filepath.Join(fooDir, "test.c") + err = os.WriteFile(foo_test_c, []byte("foo"), 0644) + require.NoError(t, err) + + handler, err := NewFilesystemHandler([]string{dir}) + require.NoError(t, err) + + tests := []struct { + info string + pattern string + matches []string + }{ + {info: "use placeholder with extension", pattern: "*.h", matches: []string{test_h, foo_bar_h}}, + {info: "use placeholder with name", pattern: "test.*", matches: []string{test_h, test_c}}, + {info: "same filename", pattern: "test.c", matches: []string{test_c, foo_test_c}}, + } + + for _, test := range tests { + t.Run(test.info, func(t *testing.T) { + request := mcp.CallToolRequest{} + request.Params.Name = "search_files" + request.Params.Arguments = map[string]any{ + "path": dir, + "pattern": test.pattern, + } + + result, err := handler.handleSearchFiles(context.Background(), request) + require.NoError(t, err) + assert.False(t, result.IsError) + assert.Len(t, result.Content, 1) + + for _, match := range test.matches { + assert.Contains(t, result.Content[0].(mcp.TextContent).Text, match) + } + }) + } +} diff --git a/go.mod b/go.mod index eeba9a7..06aed45 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.23.2 require ( github.com/gabriel-vasile/mimetype v1.4.3 + github.com/gobwas/glob v0.2.3 github.com/mark3labs/mcp-go v0.26.0 github.com/stretchr/testify v1.9.0 ) diff --git a/go.sum b/go.sum index c819acf..365a67b 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= +github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=