mirror of
https://github.com/lukaszraczylo/filepuff-mcp.git
synced 2026-10-17 05:47:33 +00:00
feat(ast_query): default to compact format for token efficiency
ast_query defaulted to verbose output (full code + up to 500 chars/match + captures), which is very token-heavy on multi-match queries. Default to compact (one line per match: file:line (kind) firstline) — roughly 5-10x fewer tokens on typical queries — while verbose remains available per-call (format=verbose) or via the default_format session pref. Updates tool description, help resource, and TestASTQueryFormatCompactDefault.
This commit is contained in:
@@ -55,16 +55,18 @@ func Epsilon() int { return 2 }
|
|||||||
|
|
||||||
// ---- Feature 1: ast_query format flag ----
|
// ---- Feature 1: ast_query format flag ----
|
||||||
|
|
||||||
func TestASTQueryFormatVerboseDefault(t *testing.T) {
|
func TestASTQueryFormatCompactDefault(t *testing.T) {
|
||||||
srv, tmpDir := newFeaturesServer(t)
|
srv, tmpDir := newFeaturesServer(t)
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
req := mcp.CallToolRequest{}
|
// Default (no format arg) is compact: one line per match, no code blocks.
|
||||||
req.Params.Arguments = map[string]interface{}{
|
args := map[string]interface{}{
|
||||||
"pattern": "func $NAME() string",
|
"pattern": "func $NAME() string",
|
||||||
"language": "go",
|
"language": "go",
|
||||||
"paths": []interface{}{tmpDir},
|
"paths": []interface{}{tmpDir},
|
||||||
}
|
}
|
||||||
|
req := mcp.CallToolRequest{}
|
||||||
|
req.Params.Arguments = args
|
||||||
res, err := srv.handleASTQuery(ctx, req)
|
res, err := srv.handleASTQuery(ctx, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
@@ -72,10 +74,19 @@ func TestASTQueryFormatVerboseDefault(t *testing.T) {
|
|||||||
if res == nil || len(res.Content) == 0 {
|
if res == nil || len(res.Content) == 0 {
|
||||||
t.Fatal("nil/empty result")
|
t.Fatal("nil/empty result")
|
||||||
}
|
}
|
||||||
text := res.Content[0].(mcp.TextContent).Text
|
if text := res.Content[0].(mcp.TextContent).Text; strings.Contains(text, "```") {
|
||||||
// verbose mode has code blocks
|
t.Errorf("compact default should NOT have code blocks, got:\n%s", text)
|
||||||
if !strings.Contains(text, "```") {
|
}
|
||||||
t.Errorf("verbose mode should have code blocks, got:\n%s", text)
|
|
||||||
|
// Verbose remains available on explicit request.
|
||||||
|
args["format"] = "verbose"
|
||||||
|
req.Params.Arguments = args
|
||||||
|
res, err = srv.handleASTQuery(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if text := res.Content[0].(mcp.TextContent).Text; !strings.Contains(text, "```") {
|
||||||
|
t.Errorf("format=verbose should have code blocks, got:\n%s", text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,10 @@ func (s *Server) resolveASTQueryParams(request mcp.CallToolRequest) (*astQueryPa
|
|||||||
if prefsFormat != "" {
|
if prefsFormat != "" {
|
||||||
p.format = prefsFormat
|
p.format = prefsFormat
|
||||||
} else {
|
} else {
|
||||||
p.format = "verbose"
|
// Default to compact (one line per match): far fewer tokens than
|
||||||
|
// verbose (full code + captures) on multi-match queries. Callers can
|
||||||
|
// opt into verbose per-call or via the default_format session pref.
|
||||||
|
p.format = "compact"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ const helpASTQuery = "# ast_query — flags and examples\n\n" +
|
|||||||
"| Flag | Effect |\n" +
|
"| Flag | Effect |\n" +
|
||||||
"|------|--------|\n" +
|
"|------|--------|\n" +
|
||||||
"| `verbose=true` | Emit `Found N match(es):` preamble (v1 behaviour). Default: false. |\n" +
|
"| `verbose=true` | Emit `Found N match(es):` preamble (v1 behaviour). Default: false. |\n" +
|
||||||
"| `format` | `verbose` (default, full code+captures) \\| `compact` (one line per match) \\| `location` (file:line only) |\n" +
|
"| `format` | `compact` (default, one line per match) \\| `verbose` (full code+captures) \\| `location` (file:line only) |\n" +
|
||||||
"| `cursor` | Opaque pagination token from a previous truncated response — fetches next page. |\n" +
|
"| `cursor` | Opaque pagination token from a previous truncated response — fetches next page. |\n" +
|
||||||
"| `max_results` | Page size (default: 100). |\n" +
|
"| `max_results` | Page size (default: 100). |\n" +
|
||||||
"| `name_exact` | Exact symbol name to match. |\n" +
|
"| `name_exact` | Exact symbol name to match. |\n" +
|
||||||
|
|||||||
@@ -251,7 +251,7 @@ func (s *Server) registerTools() {
|
|||||||
mcp.Description("Maximum number of results to return (default: 100, page size for pagination)"),
|
mcp.Description("Maximum number of results to return (default: 100, page size for pagination)"),
|
||||||
),
|
),
|
||||||
mcp.WithString("format",
|
mcp.WithString("format",
|
||||||
mcp.Description("Output format: \"verbose\" (default, full code+captures), \"compact\" (one line per match), \"location\" (file:line only)"),
|
mcp.Description("Output format: \"compact\" (default, one line per match), \"verbose\" (full code+captures), \"location\" (file:line only)"),
|
||||||
),
|
),
|
||||||
mcp.WithString("cursor",
|
mcp.WithString("cursor",
|
||||||
mcp.Description("Pagination cursor from a previous truncated response. Pass back to fetch the next page."),
|
mcp.Description("Pagination cursor from a previous truncated response. Pass back to fetch the next page."),
|
||||||
|
|||||||
Reference in New Issue
Block a user