Skip to content

Commit 236e32c

Browse files
anvansterclaude
andcommitted
feat(mcp): find_entry_points honors limit + compact — phase 2 compaction
find_entry_points was the worst output offender — telemetry showed 24 of ~42 calls returning >50k chars. Root cause: the tool schema advertises `limit` (default 50) and `compact`, and the description says "Default limit 50. Use compact=true", but FindEntryPointsParams dropped BOTH fields, so every call returned every entry point with full signature + docstring. Wire up the documented contract: limit (default 50) caps the returned vec while total_found still reports the true count; compact drops per-entry signature/docstring/description. No schema change for the caller — these params were already documented, just ignored. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 6bb77e6 commit 236e32c

1 file changed

Lines changed: 58 additions & 7 deletions

File tree

crates/codegraph-server/src/handlers/ai_query.rs

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,14 @@ pub struct FindEntryPointsParams {
119119
/// Filter by framework (e.g., "express", "fastapi", "actix")
120120
#[serde(default)]
121121
pub framework: Option<String>,
122+
/// Maximum number of entry points to return (default 50). `total_found`
123+
/// still reports the true count so the caller knows results were capped.
124+
#[serde(default)]
125+
pub limit: Option<usize>,
126+
/// Compact mode: drop per-entry signature/docstring/description for a
127+
/// much smaller response (default false).
128+
#[serde(default)]
129+
pub compact: Option<bool>,
122130
}
123131

124132
#[derive(Debug, Serialize)]
@@ -473,15 +481,30 @@ impl CodeGraphBackend {
473481
let results = self.query_engine.find_entry_points(&entry_types).await;
474482
let total_found = results.len();
475483

484+
// Honor the (previously dropped) `limit` and `compact` params that the
485+
// tool schema already advertises. Telemetry: 24 of ~42 calls returned
486+
// >50k chars because every entry point was emitted with full signature
487+
// + docstring; the documented default cap of 50 was never applied.
488+
let limit = params.limit.unwrap_or(50);
489+
let compact = params.compact.unwrap_or(false);
490+
476491
let entry_points = results
477492
.into_iter()
478-
.map(|ep| EntryPointResponse {
479-
node_id: ep.node_id.to_string(),
480-
entry_type: format!("{:?}", ep.entry_type).to_lowercase(),
481-
route: ep.route,
482-
method: ep.method,
483-
description: ep.description,
484-
symbol: symbol_info_to_response(&ep.symbol),
493+
.take(limit)
494+
.map(|ep| {
495+
let mut symbol = symbol_info_to_response(&ep.symbol);
496+
if compact {
497+
symbol.signature = None;
498+
symbol.docstring = None;
499+
}
500+
EntryPointResponse {
501+
node_id: ep.node_id.to_string(),
502+
entry_type: format!("{:?}", ep.entry_type).to_lowercase(),
503+
route: ep.route,
504+
method: ep.method,
505+
description: if compact { None } else { ep.description },
506+
symbol,
507+
}
485508
})
486509
.collect();
487510

@@ -1154,6 +1177,8 @@ mod tests {
11541177
let params = FindEntryPointsParams {
11551178
entry_type: Some("main".to_string()),
11561179
framework: None,
1180+
limit: None,
1181+
compact: None,
11571182
};
11581183

11591184
let result = backend.handle_find_entry_points(params).await.unwrap();
@@ -1196,6 +1221,8 @@ mod tests {
11961221
let params = FindEntryPointsParams {
11971222
entry_type: Some("http_handler".to_string()),
11981223
framework: None,
1224+
limit: None,
1225+
compact: None,
11991226
};
12001227

12011228
let result = backend.handle_find_entry_points(params).await.unwrap();
@@ -1247,11 +1274,35 @@ mod tests {
12471274
let params = FindEntryPointsParams {
12481275
entry_type: None,
12491276
framework: None,
1277+
limit: None,
1278+
compact: None,
12501279
};
12511280

12521281
let result = backend.handle_find_entry_points(params).await.unwrap();
12531282

12541283
assert!(result.total_found >= 2);
1284+
1285+
// limit caps the returned vec but total_found still reports the truth
1286+
// (the >50k-output fix). compact drops signature/docstring.
1287+
let capped = backend
1288+
.handle_find_entry_points(FindEntryPointsParams {
1289+
entry_type: None,
1290+
framework: None,
1291+
limit: Some(1),
1292+
compact: Some(true),
1293+
})
1294+
.await
1295+
.unwrap();
1296+
assert_eq!(capped.entry_points.len(), 1, "limit=1 must cap results");
1297+
assert!(
1298+
capped.total_found >= 2,
1299+
"total_found reports the true count"
1300+
);
1301+
assert!(
1302+
capped.entry_points[0].symbol.signature.is_none()
1303+
&& capped.entry_points[0].symbol.docstring.is_none(),
1304+
"compact must drop signature + docstring"
1305+
);
12551306
}
12561307

12571308
// ==========================================

0 commit comments

Comments
 (0)