MCP server for analyzing Python code call graphs, dependencies, and function interactions using static analysis and AI-powered call certainty classification
The server defines 8 tools with complete input schemas and descriptions. All tools follow verb_noun naming conventions (build_, list_, clear_, graph_, search_, query_, export_, call_). Descriptions are present and reasonably detailed (averaging ~150 chars), though some lack critical context about when to use them vs. similar tools. Parameter descriptions are present for most inputs. However, output schemas are NOT documented anywhere in the codebase, the tool definitions show return types as Dict[str, Any] with no schema definition. This is a critical gap for LLM reasoning. Error handling is basic, no actionable recovery guidance visible. No tool annotations (readOnlyHint/destructiveHint) despite clear read/write semantics. The code shows input validation (reject_control_chars, normalize_* functions) but error responses are not shown to be LLM-friendly. Tool composition is reasonable, each tool has a single responsibility. However, dependencies between tools (e.g., build_graph must be called before query_graph) are not explicit in descriptions.
Build a call graph for a Python project at the specified root path with configurable granularity, external imports inclusion, and call resolution strategy
For a target function, send its source code and graph-extracted callees list to Gemini API, which classifies each callee as always/conditional/unlikely/unknown execution
Clear graph cache entries, optionally clearing a specific graph or all cached graphs
Export a subgraph of the call graph in Mermaid or Graphviz (DOT) format, optionally focused on a specific node and direction
Get overview statistics of a built graph including node/edge counts, entrypoints, leaves, hotspots, and per-file breakdowns
List all currently cached graphs with their metadata
No documented output schemas for any tool. All tools return Dict[str, Any] with no field-level documentation. LLMs cannot predict what fields are in responses or plan downstream tool calls. This violates the response-shaper and tool-chain patterns.
No tool annotations (destructiveHint, readOnlyHint, idempotentHint). The clear_graph_cache tool is destructive but unmarked; build_graph with force_rebuild=true is destructive but unmarked. LLMs cannot assess risk or plan retry strategies without these hints.
Missing tool descriptions in function docstrings. build_graph, list_cached_graphs, clear_graph_cache, graph_overview, search_nodes lack docstrings explaining WHEN to use them instead of similar tools (e.g., difference between search_nodes and query_graph). Descriptions in @mcp.tool() decorators only appear in source code, not in docstrings, making them harder to discover.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | D | 54 | 2026-07-28+ | v2 |
| 2026-03-09 | F | 0 | - | v1 |
Query the graph for caller/callee relationships, dependencies, reverse dependencies, or paths between nodes
Search for nodes in the graph by name/id substring matching
Dependencies between tools are implicit, not documented. build_graph must be called first to get a graph_id, which all other tools require. This ordering is not stated in descriptions, forcing LLMs to discover it through trial and error.
No error handling guidance in tool descriptions. What happens if graph_id is invalid? What if refresh_if_stale finds no changes? What if Gemini API fails? Descriptions do not tell LLMs what to do next in failure cases.
API key handling in call_certainty_gemini: defaults to environment variable GEMINI_API_KEY if api_key parameter not provided. This is acceptable, but the description does not warn that secrets should never be passed via tool parameters. If an LLM mistakenly passes an API key in a call, it will be logged.