Skip to content

Commit 4af920e

Browse files
jgravelleclaude
andcommitted
fix: track token savings in get_file_tree and search_text
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 38a8a3e commit 4af920e

3 files changed

Lines changed: 34 additions & 3 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "jcodemunch-mcp"
3-
version = "0.2.11"
3+
version = "0.2.12"
44
description = "Token-efficient MCP server for source code exploration via tree-sitter AST parsing"
55
readme = "README.md"
66
requires-python = ">=3.10"

src/jcodemunch_mcp/tools/get_file_tree.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import time
55
from typing import Optional
66

7-
from ..storage import IndexStore
7+
from ..storage import IndexStore, record_savings, estimate_savings, cost_avoided
88
from ._utils import resolve_repo
99

1010

@@ -53,13 +53,29 @@ def get_file_tree(
5353

5454
elapsed = (time.perf_counter() - start) * 1000
5555

56+
# Token savings: sum of raw file sizes vs compact tree response
57+
store2 = IndexStore(base_path=storage_path)
58+
content_dir = store2._content_dir(owner, name)
59+
raw_bytes = 0
60+
for f in files:
61+
try:
62+
raw_bytes += os.path.getsize(content_dir / f)
63+
except OSError:
64+
pass
65+
response_bytes = len(str(tree).encode())
66+
tokens_saved = estimate_savings(raw_bytes, response_bytes)
67+
total_saved = record_savings(tokens_saved)
68+
5669
return {
5770
"repo": f"{owner}/{name}",
5871
"path_prefix": path_prefix,
5972
"tree": tree,
6073
"_meta": {
6174
"timing_ms": round(elapsed, 1),
6275
"file_count": len(files),
76+
"tokens_saved": tokens_saved,
77+
"total_tokens_saved": total_saved,
78+
**cost_avoided(tokens_saved, total_saved),
6379
},
6480
}
6581

src/jcodemunch_mcp/tools/search_text.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
"""Full-text search across indexed file contents."""
22

3+
import os
34
import time
45
from typing import Optional
56

6-
from ..storage import IndexStore
7+
from ..storage import IndexStore, record_savings, estimate_savings, cost_avoided
78
from ._utils import resolve_repo
89

910

@@ -81,6 +82,17 @@ def search_text(
8182

8283
elapsed = (time.perf_counter() - start) * 1000
8384

85+
# Token savings: raw bytes of searched files vs matched lines returned
86+
raw_bytes = 0
87+
for file_path in files[:files_searched]:
88+
try:
89+
raw_bytes += os.path.getsize(content_dir / file_path)
90+
except OSError:
91+
pass
92+
response_bytes = sum(len(m["text"].encode()) for m in matches)
93+
tokens_saved = estimate_savings(raw_bytes, response_bytes)
94+
total_saved = record_savings(tokens_saved)
95+
8496
return {
8597
"repo": f"{owner}/{name}",
8698
"query": query,
@@ -90,5 +102,8 @@ def search_text(
90102
"timing_ms": round(elapsed, 1),
91103
"files_searched": files_searched,
92104
"truncated": len(matches) >= max_results,
105+
"tokens_saved": tokens_saved,
106+
"total_tokens_saved": total_saved,
107+
**cost_avoided(tokens_saved, total_saved),
93108
},
94109
}

0 commit comments

Comments
 (0)