Skip to content

Commit f66427a

Browse files
fix(mcp): cap path-filtered search fetches
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
1 parent 04c8a4e commit f66427a

2 files changed

Lines changed: 33 additions & 14 deletions

File tree

internal/mcp/handler_query.go

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ var strictFalse = false
2222
const (
2323
defaultQueryGraphLimit = 50
2424
maxQueryGraphLimit = 500
25+
searchPathFetchFactor = 5
26+
searchPathFetchFloor = 50
27+
searchPathFetchCap = 500
2528
)
2629

2730
// largeFunctionItem summarizes one oversized function candidate.
@@ -116,14 +119,14 @@ type fileSummaryResponse struct {
116119
// nodeResponse is the typed wire payload for getNode.
117120
// @intent preserve a stable response envelope for node metadata lookups.
118121
type nodeResponse struct {
119-
ID uint `json:"id"`
120-
QualifiedName string `json:"qualified_name"`
121-
Kind model.NodeKind `json:"kind"`
122-
Name string `json:"name"`
123-
FilePath string `json:"file_path"`
124-
StartLine int `json:"start_line"`
125-
EndLine int `json:"end_line"`
126-
Language string `json:"language"`
122+
ID uint `json:"id"`
123+
QualifiedName string `json:"qualified_name"`
124+
Kind model.NodeKind `json:"kind"`
125+
Name string `json:"name"`
126+
FilePath string `json:"file_path"`
127+
StartLine int `json:"start_line"`
128+
EndLine int `json:"end_line"`
129+
Language string `json:"language"`
127130
Evidence workspaceEvidenceBlock `json:"evidence"`
128131
}
129132

@@ -205,7 +208,7 @@ func (h *handlers) search(ctx context.Context, request mcp.CallToolRequest) (*mc
205208
// that after filtering we still have up to 'limit' results.
206209
fetchLimit := limit
207210
if pathPrefix != "" {
208-
fetchLimit = max(limit*5, 50)
211+
fetchLimit = min(max(limit*searchPathFetchFactor, searchPathFetchFloor), searchPathFetchCap)
209212
}
210213

211214
nodes, err := h.deps.SearchBackend.Query(ctx, h.deps.DB, query, fetchLimit)
@@ -592,11 +595,11 @@ func compactQueryTargetAmbiguity(target string, matches []querypkg.CandidateMatc
592595
// listGraphStatsResponse is the serialized payload for graph statistics.
593596
// @intent preserve a stable typed JSON response for graph statistics without changing the wire format.
594597
type listGraphStatsResponse struct {
595-
TotalNodes int64 `json:"total_nodes"`
596-
TotalEdges int64 `json:"total_edges"`
597-
NodesByKind map[string]int64 `json:"nodes_by_kind"`
598-
NodesByLanguage map[string]int64 `json:"nodes_by_language"`
599-
EdgesByKind map[string]int64 `json:"edges_by_kind"`
598+
TotalNodes int64 `json:"total_nodes"`
599+
TotalEdges int64 `json:"total_edges"`
600+
NodesByKind map[string]int64 `json:"nodes_by_kind"`
601+
NodesByLanguage map[string]int64 `json:"nodes_by_language"`
602+
EdgesByKind map[string]int64 `json:"edges_by_kind"`
600603
Evidence workspaceEvidenceBlock `json:"evidence"`
601604
}
602605

internal/mcp/handlers_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,20 @@ func TestHandler_Search_PathFilter_RespectsPathBoundary(t *testing.T) {
355355
}
356356
}
357357

358+
func TestHandler_Search_PathFilter_CapsInternalFetchLimit(t *testing.T) {
359+
deps := setupTestDeps(t)
360+
backend := &failSearchBackend{}
361+
deps.SearchBackend = backend
362+
363+
result := callTool(t, deps, "search", map[string]any{"query": "handle", "path": "internal/api", "limit": 500})
364+
if result.IsError {
365+
t.Fatalf("search returned error: %s", getTextContent(result))
366+
}
367+
if backend.queryLimit != 500 {
368+
t.Fatalf("Query limit = %d, want 500 cap", backend.queryLimit)
369+
}
370+
}
371+
358372
func TestHandler_GetAnnotation(t *testing.T) {
359373
deps := setupTestDeps(t)
360374
ctx := context.Background()
@@ -3632,6 +3646,7 @@ func Svc() {}
36323646
type failSearchBackend struct {
36333647
err error
36343648
rebuildCalls int
3649+
queryLimit int
36353650
}
36363651

36373652
func (f *failSearchBackend) Rebuild(ctx context.Context, db *gorm.DB) error {
@@ -3650,6 +3665,7 @@ func (f *failSearchBackend) PurgeNamespace(ctx context.Context, db *gorm.DB) err
36503665
func (f *failSearchBackend) Migrate(db *gorm.DB) error { return nil }
36513666

36523667
func (f *failSearchBackend) Query(ctx context.Context, db *gorm.DB, query string, limit int) ([]model.Node, error) {
3668+
f.queryLimit = limit
36533669
return nil, nil
36543670
}
36553671

0 commit comments

Comments
 (0)