From 15bef512b4f91c3fca65c8dad1d9e5c26ef764c9 Mon Sep 17 00:00:00 2001 From: Martin Vogel Date: Wed, 12 Aug 2026 20:04:46 +0200 Subject: [PATCH 01/26] feat(mcp): make tool output lean and lossless Signed-off-by: Martin Vogel --- README.md | 9 +- .../src/components/NodeDetailPanel.test.tsx | 6 + graph-ui/src/components/NodeDetailPanel.tsx | 2 + graph-ui/src/components/StatsTab.test.tsx | 7 +- graph-ui/src/hooks/useProjects.test.tsx | 86 + graph-ui/src/hooks/useProjects.ts | 71 +- graph-ui/tsconfig.tsbuildinfo | 2 +- scripts/smoke-test.sh | 14 +- src/cli/hook_augment.c | 170 +- src/cli/progress_sink.c | 41 + src/cypher/cypher.c | 115 +- src/cypher/cypher.h | 4 + src/foundation/log.c | 2 +- src/foundation/log.h | 2 +- src/main.c | 38 +- src/mcp/compact_out.c | 644 ++ src/mcp/compact_out.h | 23 + src/mcp/mcp.c | 5721 +++++++++++++---- src/mcp/mcp_internal.h | 9 + src/store/store.c | 91 +- src/store/store.h | 10 + src/ui/http_server.c | 3 +- tests/scale_contract.sh | 9 +- tests/test_cli.c | 153 + tests/test_cypher.c | 173 +- tests/test_daemon_runtime.c | 3 + tests/test_httpd.c | 29 +- tests/test_incremental.c | 20 +- tests/test_index_resilience.c | 7 +- tests/test_log.c | 41 +- tests/test_mcp.c | 3558 +++++++++- tests/windows/test_daemon_lifecycle.py | 23 +- tests/windows/test_daemon_stability.py | 6 +- 33 files changed, 9436 insertions(+), 1656 deletions(-) create mode 100644 graph-ui/src/hooks/useProjects.test.tsx diff --git a/README.md b/README.md index 87cf17920..63c83703b 100644 --- a/README.md +++ b/README.md @@ -576,7 +576,11 @@ Every MCP tool can be invoked as a local, one-shot command. CLI tools neither st Commands that mutate graph data use shared OS-backed, per-project locks. This serializes conflicting work from CLI and MCP sessions on the same project while allowing unrelated projects to proceed independently. -When stderr is an interactive terminal, the CLI automatically shows lifecycle and indexing progress. Pass `--progress` to force the same feedback when stderr is redirected or the command is run non-interactively. Progress is written only to stderr; stdout remains reserved for the command result, so pipes and scripts stay machine-safe. Pass `--json` when the full MCP result envelope is needed. +When stderr is an interactive terminal, the CLI automatically shows lifecycle and indexing progress. Pass `--progress` to force the same feedback when stderr is redirected or the command is run non-interactively. Routine informational logs are quiet by default; pass outer `cli --verbose` to include them. Progress and logs use stderr while stdout remains reserved for the command result. Read tools return a compact tree by default; pass a tool's `--format json` for machine-readable payload JSON, or outer `--json` for the full MCP envelope. + +Large compact-tree tables may start with a response-local `
_refs` directory and an explicit `
_ref_rule`. A cell such as `@0+handler.go` reconstructs to ref `0`'s prefix plus `handler.go`. References are local to that sibling `
` table and expansion is non-recursive: entries inside `
_refs` are always literal prefixes. This is limited to declared path and qualified-name columns and activates only when that table is at least 15% and 64 bytes smaller. Search and trace likewise render direct and prefix-grouped tree shapes and keep the smaller complete representation, so singleton or scattered answers do not pay directory overhead. Keys are declared once per table but never cryptically abbreviated, and `--format json` keeps stable literal strings for machine consumers. These are deterministic model-neutral byte savings that normally reduce tokens; exact token counts still depend on the caller's tokenizer. + +Lean responses truncate semantically, never by cutting arbitrary bytes from code or identifiers. Ranked graph rows are retained ahead of raw grep rows and diagnostic summaries; omitted rows/sections report totals, `has_more`, and a strictly advancing continuation offset or cursor. If even the first whole row cannot fit, CBM asks for a higher budget and emits no self-looping cursor. `max_output_tokens` is model-neutral sizing guidance: CBM enforces a deterministic ceiling of four UTF-8 bytes per requested token, so it is not a tokenizer-exact count. Detail flags such as `diagnostics`, `source_mode`, and `detail` opt into heavier fields. `search_code` additionally exposes `raw_limit`, `directory_limit`, `match_limit`, and `source_max_lines`; its default retains eight match locations per graph result and reports the exact `matches_omitted` remainder. `detect_changes` pages changed files, impacted symbols, and module summaries independently. Use `cli --help` to see the flags generated from that tool's input schema: @@ -591,7 +595,8 @@ codebase-memory-mcp cli query_graph --project my-project --query 'MATCH (f:Funct # Force human-readable progress without contaminating stdout. codebase-memory-mcp cli --progress index_repository --repo-path /path/to/repo -codebase-memory-mcp cli search_graph --project my-project --label Function | jq '.results[].name' +codebase-memory-mcp cli search_graph --project my-project --label Function --format json +codebase-memory-mcp cli list_projects --format json --detail stats | jq '.projects[].name' ``` JSON arguments can also be piped on stdin. Inline JSON remains accepted for backward compatibility but is deprecated in favor of flags, `--args-file`, or stdin. diff --git a/graph-ui/src/components/NodeDetailPanel.test.tsx b/graph-ui/src/components/NodeDetailPanel.test.tsx index 5a9455d09..12c72b1a4 100644 --- a/graph-ui/src/components/NodeDetailPanel.test.tsx +++ b/graph-ui/src/components/NodeDetailPanel.test.tsx @@ -68,6 +68,12 @@ describe("NodeDetailPanel code preview + deep-link", () => { /* …but was NOT parsed into a real