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

Method handleCallers

src/mcp/tools.ts:1644–1712  ·  view source on GitHub ↗

* Handle codegraph_callers

(args: Record<string, unknown>)

Source from the content-addressed store, hash-verified

1642 * Handle codegraph_callers
1643 */
1644 private async handleCallers(args: Record<string, unknown>): Promise<ToolResult> {
1645 const symbol = this.validateString(args.symbol, 'symbol');
1646 if (typeof symbol !== 'string') return symbol;
1647
1648 const cg = this.getCodeGraph(args.projectPath as string | undefined);
1649 const limit = clamp((args.limit as number) || 20, 1, 100);
1650 const fileFilter = typeof args.file === 'string' ? args.file : undefined;
1651
1652 const allMatches = this.findAllSymbols(cg, symbol);
1653 if (allMatches.nodes.length === 0) {
1654 return this.textResult(`Symbol "${symbol}" not found in the codebase`);
1655 }
1656
1657 const { groups, filteredOut } = this.groupDefinitions(allMatches.nodes, fileFilter);
1658 const filterNote = filteredOut
1659 ? `\n\n> **Note:** no definition of "${symbol}" matches file "${fileFilter}" — showing all definitions instead.`
1660 : '';
1661
1662 const collect = (defNodes: Node[]) => {
1663 const seen = new Set<string>();
1664 const callers: Node[] = [];
1665 const labels = new Map<string, string>();
1666 for (const node of defNodes) {
1667 for (const c of cg.getCallers(node.id)) {
1668 if (!seen.has(c.node.id)) {
1669 seen.add(c.node.id);
1670 callers.push(c.node);
1671 const label = this.edgeLabel(c.edge);
1672 if (label) labels.set(c.node.id, label);
1673 }
1674 }
1675 }
1676 return { callers, labels };
1677 };
1678
1679 // Single definition (or same-file overloads): the familiar flat list.
1680 if (groups.length === 1) {
1681 const { callers, labels } = collect(groups[0]!);
1682 if (callers.length === 0) {
1683 return this.textResult(`No callers found for "${symbol}"${allMatches.note}${filterNote}`);
1684 }
1685 // A successful `file` narrowing makes the multi-symbol aggregation note
1686 // stale — suppress it.
1687 const note = fileFilter && !filteredOut ? '' : allMatches.note;
1688 const formatted = this.formatNodeList(callers.slice(0, limit), `Callers of ${symbol}`, labels) + note + filterNote;
1689 return this.textResult(this.truncateOutput(formatted));
1690 }
1691
1692 // Multiple DISTINCT definitions (#764): one section per definition so an
1693 // agent never mistakes one app's callers for another's. Narrow with
1694 // `file` to focus a single definition.
1695 const lines: string[] = [
1696 `**Callers of ${symbol} — ${groups.length} distinct definitions (narrow with \`file\`)**`,
1697 ];
1698 for (const group of groups) {
1699 const { callers, labels } = collect(group);
1700 lines.push('', this.definitionHeading(group));
1701 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