MCPcopy Create free account
hub / github.com/colbymchenry/codegraph / handleCallers

Method handleCallers

src/mcp/tools.ts:1572–1640  ·  view source on GitHub ↗

* Handle codegraph_callers

(args: Record<string, unknown>)

Source from the content-addressed store, hash-verified

1570 * Handle codegraph_callers
1571 */
1572 private async handleCallers(args: Record<string, unknown>): Promise<ToolResult> {
1573 const symbol = this.validateString(args.symbol, 'symbol');
1574 if (typeof symbol !== 'string') return symbol;
1575
1576 const cg = this.getCodeGraph(args.projectPath as string | undefined);
1577 const limit = clamp((args.limit as number) || 20, 1, 100);
1578 const fileFilter = typeof args.file === 'string' ? args.file : undefined;
1579
1580 const allMatches = this.findAllSymbols(cg, symbol);
1581 if (allMatches.nodes.length === 0) {
1582 return this.textResult(`Symbol "${symbol}" not found in the codebase`);
1583 }
1584
1585 const { groups, filteredOut } = this.groupDefinitions(allMatches.nodes, fileFilter);
1586 const filterNote = filteredOut
1587 ? `\n\n> **Note:** no definition of "${symbol}" matches file "${fileFilter}" — showing all definitions instead.`
1588 : '';
1589
1590 const collect = (defNodes: Node[]) => {
1591 const seen = new Set<string>();
1592 const callers: Node[] = [];
1593 const labels = new Map<string, string>();
1594 for (const node of defNodes) {
1595 for (const c of cg.getCallers(node.id)) {
1596 if (!seen.has(c.node.id)) {
1597 seen.add(c.node.id);
1598 callers.push(c.node);
1599 const label = this.edgeLabel(c.edge);
1600 if (label) labels.set(c.node.id, label);
1601 }
1602 }
1603 }
1604 return { callers, labels };
1605 };
1606
1607 // Single definition (or same-file overloads): the familiar flat list.
1608 if (groups.length === 1) {
1609 const { callers, labels } = collect(groups[0]!);
1610 if (callers.length === 0) {
1611 return this.textResult(`No callers found for "${symbol}"${allMatches.note}${filterNote}`);
1612 }
1613 // A successful `file` narrowing makes the multi-symbol aggregation note
1614 // stale — suppress it.
1615 const note = fileFilter && !filteredOut ? '' : allMatches.note;
1616 const formatted = this.formatNodeList(callers.slice(0, limit), `Callers of ${symbol}`, labels) + note + filterNote;
1617 return this.textResult(this.truncateOutput(formatted));
1618 }
1619
1620 // Multiple DISTINCT definitions (#764): one section per definition so an
1621 // agent never mistakes one app's callers for another's. Narrow with
1622 // `file` to focus a single definition.
1623 const lines: string[] = [
1624 `**Callers of ${symbol} — ${groups.length} distinct definitions (narrow with \`file\`)**`,
1625 ];
1626 for (const group of groups) {
1627 const { callers, labels } = collect(group);
1628 lines.push('', this.definitionHeading(group));
1629 if (callers.length === 0) {

Callers 1

dispatchToolMethod · 0.95

Calls 12

validateStringMethod · 0.95
getCodeGraphMethod · 0.95
findAllSymbolsMethod · 0.95
textResultMethod · 0.95
groupDefinitionsMethod · 0.95
formatNodeListMethod · 0.95
truncateOutputMethod · 0.95
definitionHeadingMethod · 0.95
clampFunction · 0.90
collectFunction · 0.85
getMethod · 0.65
joinMethod · 0.45

Tested by

no test coverage detected