diff --git a/internal/server/features_test.go b/internal/server/features_test.go index 5641e2b..d1c35e3 100644 --- a/internal/server/features_test.go +++ b/internal/server/features_test.go @@ -55,16 +55,18 @@ func Epsilon() int { return 2 } // ---- Feature 1: ast_query format flag ---- -func TestASTQueryFormatVerboseDefault(t *testing.T) { +func TestASTQueryFormatCompactDefault(t *testing.T) { srv, tmpDir := newFeaturesServer(t) ctx := context.Background() - req := mcp.CallToolRequest{} - req.Params.Arguments = map[string]interface{}{ + // Default (no format arg) is compact: one line per match, no code blocks. + args := map[string]interface{}{ "pattern": "func $NAME() string", "language": "go", "paths": []interface{}{tmpDir}, } + req := mcp.CallToolRequest{} + req.Params.Arguments = args res, err := srv.handleASTQuery(ctx, req) if err != nil { t.Fatalf("unexpected error: %v", err) @@ -72,10 +74,19 @@ func TestASTQueryFormatVerboseDefault(t *testing.T) { if res == nil || len(res.Content) == 0 { t.Fatal("nil/empty result") } - text := res.Content[0].(mcp.TextContent).Text - // verbose mode has code blocks - if !strings.Contains(text, "```") { - t.Errorf("verbose mode should have code blocks, got:\n%s", text) + if text := res.Content[0].(mcp.TextContent).Text; strings.Contains(text, "```") { + t.Errorf("compact default should NOT 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) } } diff --git a/internal/server/handlers_ast.go b/internal/server/handlers_ast.go index ebc91a7..8865c5f 100644 --- a/internal/server/handlers_ast.go +++ b/internal/server/handlers_ast.go @@ -67,7 +67,10 @@ func (s *Server) resolveASTQueryParams(request mcp.CallToolRequest) (*astQueryPa if prefsFormat != "" { p.format = prefsFormat } 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" } } diff --git a/internal/server/help_content.go b/internal/server/help_content.go index 5d30dbe..1414609 100644 --- a/internal/server/help_content.go +++ b/internal/server/help_content.go @@ -75,7 +75,7 @@ const helpASTQuery = "# ast_query — flags and examples\n\n" + "| Flag | Effect |\n" + "|------|--------|\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" + "| `max_results` | Page size (default: 100). |\n" + "| `name_exact` | Exact symbol name to match. |\n" + diff --git a/internal/server/server.go b/internal/server/server.go index 8afaf9a..13576da 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -251,7 +251,7 @@ func (s *Server) registerTools() { mcp.Description("Maximum number of results to return (default: 100, page size for pagination)"), ), 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.Description("Pagination cursor from a previous truncated response. Pass back to fetch the next page."),