Skip to main content
Glama

Build a Call Graph

call_graph
Read-onlyIdempotent

Trace C# call graphs from a method name to follow callees or callers, limit depth, and return caller-callee edges with constructor and interface-contract links.

Instructions

Build a depth-limited call graph rooted at a method NAME. direction='callees' follows project-internal calls outward; direction='callers' follows the inverse (who calls this). Returns (caller, callee) edges using method-lookup keys, cycle-safe and capped at 500 edges (truncated flag). A creation (new X(...)) is an edge to the constructor it binds, keyed 'Ns.X.X(params)', and both directions walk on through a constructor: into what it calls and creates, out to the code that creates the object. A local function's key ends in '@::', character offsets rather than a line ('localFunctionKeyNote' repeats this when the answer holds one). A bare name is rooted at the name, NOT at one symbol: EVERY same-named declaration in the solution is a root and the graph is their union, so a common name (e.g. 'ExecuteAsync') can pull in unrelated members and inflate the payload. The qualified 'Type.Method' form roots only that type's declarations of the name, overloads included. With direction='callers' every node also brings in the callers of the interface and abstract members it implements, at every hop as impact_of_change does (a call through the contract is recorded there); 'viaContract' names those members with their implementation counts (one implementation: exact, several: a union) and the nodes that brought them in ('creditedBy'). 'rootedAt' lists the declarations actually walked - check it when the result looks too big (then re-query a rarer or qualified name) and when it is empty (the name resolved to nothing, which an empty edge list alone does not tell you).

Tool call template

Replace each placeholder with a value matching the input schema. Only required parameters are included; add optional parameters as needed.

{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "arguments": {
      "sessionId": "<sessionId>",
      "method": "<method>"
    },
    "name": "call_graph"
  }
}

Input Schema

NameRequiredDescriptionDefault
depthNoMax traversal depth (1-10). Default 2.
methodYesThe root method's name, bare or as 'Type.Method'.
directionNo'callees' (default) or 'callers'.callees
sessionIdYesThe session_id returned by analyze_solution. Also takes an absolute .sln/.slnx/.slnf path, analyzed on first use.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changedv0.5.46517
    • changedInput schema / properties / method / description
      Previous value: -"The root method's name."New value: +"The root method's name, bare or as 'Type.Method'."
  2. Changed1 schema field changedv0.5.46513
    • changedInput schema / properties / sessionId / description
      Previous value: -"The session_id returned by analyze_solution."New value: +"The session_id returned by analyze_solution. Also takes an absolute .sln/.slnx/.slnf path, analyzed on first use."
  3. First observed

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare a safe, idempotent read, but the description goes well beyond them: cycle safety, a hard 500-edge cap with a truncation flag, and exactly what happens at each hop through constructors. It also discloses the contract-expansion side effect of direction='callers' (viaContract, creditedBy) and how interface/abstract callers are credited, which no annotation conveys.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

It is front-loaded with the core purpose and nearly every sentence carries unique information, but it is one very dense paragraph with multi-clause sentences (the constructor and local-function key sentences especially) that make it hard to scan. Some detail, such as restating the localFunctionKeyNote behavior, could be tightened.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, so the description must carry return semantics, and it does: edges as (caller, callee) pairs, the truncated flag, rootedAt, viaContract with implementation counts, creditedBy, and local-function key formats. An agent has enough to call this correctly and to interpret an empty or oversized result.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3, but the description adds real meaning the schema lacks: a bare `method` roots EVERY same-named declaration in the solution while 'Type.Method' roots only that type's overloads, and direction changes what nodes are returned. Only `depth` gets no elaboration beyond the schema's own 1-10 description.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb and resource ('Build a depth-limited call graph rooted at a method NAME') and immediately scopes it by the direction parameter. It is clearly distinguishable from siblings like find_usages or impact_of_change because it returns (caller, callee) edges rather than usages or change impact.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete operational guidance: use the qualified 'Type.Method' form when a bare name inflates the payload, check 'rootedAt' when the result looks too big or is empty, and re-query a rarer name. It also tells the agent that direction='callers' behaves like impact_of_change. It stops short of an explicit statement of when not to use this tool versus find_usages or calls_external.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.