Skip to content

Commit 601cf99

Browse files
committed
feat(search_files): support glob pattern
1 parent 6d95ed3 commit 601cf99

File tree

4 files changed

+71
-2
lines changed

4 files changed

+71
-2
lines changed

filesystemserver/handler.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"time"
1414

1515
"github.com/gabriel-vasile/mimetype"
16+
"github.com/gobwas/glob"
1617
"github.com/mark3labs/mcp-go/mcp"
1718
"slices"
1819
)
@@ -252,7 +253,7 @@ func (fs *FilesystemHandler) searchFiles(
252253
rootPath, pattern string,
253254
) ([]string, error) {
254255
var results []string
255-
pattern = strings.ToLower(pattern)
256+
globPattern := glob.MustCompile(pattern)
256257

257258
err := filepath.Walk(
258259
rootPath,
@@ -266,7 +267,7 @@ func (fs *FilesystemHandler) searchFiles(
266267
return nil // Skip invalid paths
267268
}
268269

269-
if strings.Contains(strings.ToLower(info.Name()), pattern) {
270+
if globPattern.Match(info.Name()) {
270271
results = append(results, path)
271272
}
272273
return nil

filesystemserver/handler_test.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,68 @@ func TestReadfile_NoAccess(t *testing.T) {
6868
assert.True(t, result.IsError)
6969
assert.Contains(t, fmt.Sprint(result.Content[0]), "access denied - path outside allowed directories")
7070
}
71+
72+
func TestSearchFiles_Pattern(t *testing.T) {
73+
74+
// setting up test folder
75+
// tmpDir/
76+
// - foo/
77+
// - bar.h
78+
// - test.c
79+
// - test.h
80+
// - test.c
81+
82+
dir := t.TempDir()
83+
test_h := filepath.Join(dir, "test.h")
84+
err := os.WriteFile(test_h, []byte("foo"), 0644)
85+
require.NoError(t, err)
86+
87+
test_c := filepath.Join(dir, "test.c")
88+
err = os.WriteFile(test_c, []byte("foo"), 0644)
89+
require.NoError(t, err)
90+
91+
fooDir := filepath.Join(dir, "foo")
92+
err = os.MkdirAll(fooDir, 0755)
93+
require.NoError(t, err)
94+
95+
foo_bar_h := filepath.Join(fooDir, "bar.h")
96+
err = os.WriteFile(foo_bar_h, []byte("foo"), 0644)
97+
require.NoError(t, err)
98+
99+
foo_test_c := filepath.Join(fooDir, "test.c")
100+
err = os.WriteFile(foo_test_c, []byte("foo"), 0644)
101+
require.NoError(t, err)
102+
103+
handler, err := NewFilesystemHandler([]string{dir})
104+
require.NoError(t, err)
105+
106+
tests := []struct {
107+
info string
108+
pattern string
109+
matches []string
110+
}{
111+
{info: "use placeholder with extension", pattern: "*.h", matches: []string{test_h, foo_bar_h}},
112+
{info: "use placeholder with name", pattern: "test.*", matches: []string{test_h, test_c}},
113+
{info: "same filename", pattern: "test.c", matches: []string{test_c, foo_test_c}},
114+
}
115+
116+
for _, test := range tests {
117+
t.Run(test.info, func(t *testing.T) {
118+
request := mcp.CallToolRequest{}
119+
request.Params.Name = "search_files"
120+
request.Params.Arguments = map[string]any{
121+
"path": dir,
122+
"pattern": test.pattern,
123+
}
124+
125+
result, err := handler.handleSearchFiles(context.Background(), request)
126+
require.NoError(t, err)
127+
assert.False(t, result.IsError)
128+
assert.Len(t, result.Content, 1)
129+
130+
for _, match := range test.matches {
131+
assert.Contains(t, result.Content[0].(mcp.TextContent).Text, match)
132+
}
133+
})
134+
}
135+
}

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ go 1.23.2
44

55
require (
66
github.com/gabriel-vasile/mimetype v1.4.3
7+
github.com/gobwas/glob v0.2.3
78
github.com/mark3labs/mcp-go v0.29.0
89
github.com/stretchr/testify v1.9.0
910
)

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk
44
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
55
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
66
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
7+
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
8+
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
79
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
810
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
911
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=

0 commit comments

Comments
 (0)