V2/token optimization (#11)

* v2.0: token-optimization overhaul

Additive (backward-compatible flags):
- file_read: skeleton mode, strip (imports/license/block_comments),
  compact_line_numbers, 8-char etag with prefix-match compat
- ast_query: format=verbose|compact|location, pagination cursor
- file_search: cluster mode, pagination cursor
- lsp_query (references): compact output

Breaking (v2):
- Preambles removed; opt-in verbose=true restores
- edit_apply: response=count|diff|none, default count
- ping tool removed
- symbol_at/find_definition/find_references merged into lsp_query
- Tool descriptions trimmed -83%, help moved to filepuff://help/<tool>
- Batch file_read dedups by etag

Protocol:
- ResourceLink returned for file_read >64 KiB (force_inline override)
- OnAfterInitialize hook reads capabilities.experimental.filepuff
  for session defaults (default_format, default_max_results,
  default_cluster, compact_refs, line_numbers,
  resource_link_threshold)

* fix: drop --max-total-count from ripgrep args

The flag does not exist in stable ripgrep (confirmed up to 15.1.0 --
"unrecognized flag --max-total-count, similar flags that are
available: --max-count"). Every file_search call failed on hosts with
stock rg. --max-count is per-file, not a drop-in replacement, so rely
on the in-process truncation in parseOutput that was already the
documented safety net.
This commit is contained in:
2026-04-19 19:56:49 +01:00
committed by GitHub
parent b131c1edd3
commit 5ad975ee7a
26 changed files with 4909 additions and 507 deletions
+49 -22
View File
@@ -4,12 +4,10 @@ package server
import (
"context"
"fmt"
"os"
"strings"
"github.com/lukaszraczylo/mcp-filepuff/internal/edit"
"github.com/lukaszraczylo/mcp-filepuff/pkg/errors"
"github.com/lukaszraczylo/mcp-filepuff/pkg/protocol"
"github.com/mark3labs/mcp-go/mcp"
)
@@ -82,27 +80,56 @@ func (s *Server) handleEdit(ctx context.Context, request mcp.CallToolRequest) (*
return mcp.NewToolResultError(result.Error), nil
}
// compact_response: return just the modified symbol instead of the full diff
if request.GetBool("compact_response", false) && selectorName != "" {
if content, readErr := os.ReadFile(file); readErr == nil {
if start, end, found := s.resolveSymbolLines(ctx, file, content, selectorName, protocol.SymbolKind("")); found {
lines := splitLines(string(content))
var sb strings.Builder
sb.WriteString(fmt.Sprintf("**Edit Applied** — %s (L%d-L%d):\n\n", selectorName, start, end))
for i := start - 1; i < end && i < len(lines); i++ {
sb.WriteString(fmt.Sprintf("%4d| %s\n", i+1, lines[i]))
}
return mcp.NewToolResultText(sb.String()), nil
}
}
// fall through to diff if symbol lookup fails
// Determine response mode.
// compact_response is a deprecated alias for response="count".
respMode := request.GetString("response", "count")
if request.GetBool("compact_response", false) {
// Deprecated: use response=count
respMode = "count"
}
var output strings.Builder
output.WriteString("**Edit Applied Successfully**\n\n")
output.WriteString("Diff:\n```diff\n")
output.WriteString(result.Diff)
output.WriteString("```\n")
switch respMode {
case "none":
return mcp.NewToolResultText(""), nil
return mcp.NewToolResultText(output.String()), nil
case "count":
// Compute +added/-removed line counts from the unified diff.
added, removed := countDiffLines(result.Diff)
return mcp.NewToolResultText(fmt.Sprintf("+%d -%d", added, removed)), nil
case "diff":
var output strings.Builder
output.WriteString("Diff:\n```diff\n")
output.WriteString(result.Diff)
output.WriteString("```\n")
return mcp.NewToolResultText(output.String()), nil
default:
// Fallback: treat unknown values as "diff" for safety.
var output strings.Builder
output.WriteString("Diff:\n```diff\n")
output.WriteString(result.Diff)
output.WriteString("```\n")
return mcp.NewToolResultText(output.String()), nil
}
}
// countDiffLines counts added (+) and removed (-) lines in a unified diff string.
func countDiffLines(diff string) (added, removed int) {
for _, line := range strings.Split(diff, "\n") {
if len(line) == 0 {
continue
}
switch line[0] {
case '+':
if !strings.HasPrefix(line, "+++") {
added++
}
case '-':
if !strings.HasPrefix(line, "---") {
removed++
}
}
}
return
}