Skip to content
verify mcp Beta VerifyMCP is currently in beta. If you notice any issues, get in touch and we’ll put it right.

Benzi

PYPI · BENZI-MCP

Compiler-backed code intelligence: calls, data flow, references and class hierarchy as tools.

Available components

+7 this week 69 Trust /100

Last scanned (23 hours ago)

Scores higher than 68% of PyPI servers

Category Code Search and Documentation

Trust breakdown (7 categories)

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. How we score → Why this is hard to score →

Supply Chain Security99
  • No malware found by supply-chain analysis.Pass
  • No known CVEs affecting this package version or its production dependencies.Pass
  • Runs setuptools.build_meta at install time, a recognised build step with no custom scripting around it. View diagnostics → Pass
  • 4 of 30 dependencies flagged as unhealthy. View diagnostics → Partial
Provenance & Transparency32
Schema Quality & AI Usability67
  • AI-judged instruction clarity (excellent).Pass
  • Context-footprint check failed: tool/resource definitions use about 5629 tokens (~268/item across 21 items; 21 tools + 0 resources), over budget; trim descriptions and params. See how to fix → Fail
  • Usage-examples check failed: none of the tools include examples. See how to fix → Fail
Stability & Change Management47
  • Stability observed for 14 of 30 days with no destabilising changes; credit accrues until the full window elapses.Partial
Tool Coverage87
  • 100% of tools have a non-trivial description (not blank, and not just the tool's name).Pass
  • 61% of tool parameters carry a description.Partial
Tool Safety100
  • No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.Pass
  • We read all 21 captured tool definition(s), and no name or description among them implies an irreversible operation.Pass
  • An AI judge read all 22 captured unit(s) of tool text and found none that tries to manipulate the model reading it.Pass
Capabilities20
  • Spec-recency check failed: implements MCP spec 2024-11-05; the latest is 2026-07-28. See how to fix → Fail
Changelog

Every change we have recorded for this component, newest first. Security-relevant changes are always shown. ▲ marks a change for the better, ▼ a change for the worse; unmarked changes are neutral.

  • 17 Oct 26 +1

    No change was recorded against any check on this day. Stability & Change Management went from 43 to 47. That category is still filling its 30-day observation window: 13 days of observed history at the previous scan, 14 at this one. The score rises as the window fills, whether or not the server changes.

  • 15 Oct 26 +32
    • Injection markers: unverified → pass ▲ security
    • MCP protocol: unverified → fail ▼ functional
    • Schema quality: 309 → 268 ▲ functional
    • Tool coverage: unverified → 100 ▲ functional
    • Stability: unverified → 0.40 ▲ functional
    • Package version: 0.1.3 → 0.1.6 functional
  • 12 Oct 26 −26
    • Tool safety: pass → unverified ▼ security
    • Stability: Stability not yet verified: we do not have a sandbox capture of the MCP schema this version of the package serves yet. security
    • Capabilities: fail → unverified ▼ functional
    • Tool coverage: 100 → unverified ▼ functional
    • Schema quality: Schema quality not yet verified: we do not have a sandbox capture of the MCP schema this version of the package serves yet. functional
    • Package version: 0.1.3 → 0.1.5 functional
  • 4 Oct 26 +15
    • Malware scan: unverified → pass ▲ security
  • 3 Oct 26 +26
    • Injection markers: unverified → pass ▲ security
    • Malware scan: unverified → pass ▲ security
    • First check of Judged manipulation: pass security
    • Stability: Stability not yet verified: not enough scan history yet (needs a 30-day window). security
    • MCP protocol: unverified → fail ▼ functional
    • Tool coverage: unverified → 100 ▲ functional
    • First check of Tool coverage: 60 functional
    • First check of Schema quality: fail functional
    • First check of Schema quality: excellent functional
    • First check of Destructive annotations: pass functional
    • First check of Schema quality: fail functional
    • Package version: 0.1.1 → 0.1.3 functional
    • Package version: 0.1.1 → 0.1.2 functional
  • 2 Oct 26 21

    First indexed and scored.

Diagnostics

Diagnostic detail from the automated scan of this channel: what the scanner observed at each step, so you can see exactly where a check passed or failed. It is informational only and never changes the trust score.

Captured 17 Oct 2026 · Analysed pypi/benzi-mcp@0.1.6

Provenance No attestation

The registry publishes no build provenance for this version, so there is nothing to verify.

Result No attestation
Ecosystem pypi
Reason No attestation published

Background: How many MCP packages publish verified provenance →

Install scripts 1 script
Hook Tier Command
build_backend allowlisted setuptools.build_meta

Background: Why install scripts are a supply-chain risk →

Dependencies 30 packages
Packages resolved 30
Stale 4
Tree resolution Complete

Background: SBOMs and build attestations, explained →

MCP tools · 21 exposed · ~3,759 tokens

The tools this component advertises to a client, with an estimated token cost for each. Expand a tool to see its parameters and schema. The per-tool counts are indicative and are not scored directly; the schema's total context footprint is one signal in Schema Quality & AI Usability. A tool's description is untrusted text the model reads on every call, which is what makes this list a security surface and not just an inventory: how tool poisoning works →

Tool Tokens
backflow ~205

Where does this value come from? Reverse DATAFLOW (mirror: forwardflow) -- what FEEDS a function's parameters, in TWO tiers. TIER 1: per proven call site, the raw argument EXPRESSION bound to the parameter it lands on -- `data` is fed `req.body` from `handle` at app.py:40. TIER 2: each expression walked BACKWARD through the caller's assignments and up the call graph to where the value ORIGINATES (literal, constant, a call's return, an import) or an honest wall; depth-capped, exact or stopped, never guessed. A parameter a caller OMITTED comes back "defaulted" with the declared default and how many sites took it -- distinct from "no_static_feed" (nothing feeds it, no default). Best-effort on *args/**kwargs: a spread stays unresolved rather than guessed (as in trace_path).

NameTypeReqDescription
name_or_idstringyes–

No output schema declared.

No examples provided.

benzi_grep ~377

Find TEXT -- a literal, a comment, an error string, a CSS class, an HTML id, a partial token -- inside the files the map INDEXES: analyzed code files plus the markup files (HTML/CSS/DOM-js) the code graph doesn't parse. It does NOT reach UNINDEXED files: a language with no grammar, a .sql, a fixture (list_unlisted_files inventories them). There, this returns "no matches" whether or not the text is present -- so for anything unindexed use your own grep, which has no such limit. The PATTERN IS A PYTHON REGEX, not a literal -- escape ( ) . * for literal characters (`\.pipe\(`). Each match carries its ENCLOSING SYMBOL (`in` -- a usable id), so it locates the handler, not just a line. Returns {path, line, in, text}; uncapped, true total always reported. `context` gives N lines around each hit (like grep -C, skips a follow-up read_source); `multiline` for patterns spanning lines.

NameTypeReqDescription
contextinteger–optional -- lines of context to return around each hit (like grep -C); default 0
multilineboolean–optional -- search whole-file with . matching newlines, for a pattern that spans lines; default false
pathstring–optional -- only files whose path contains this substring
patternstringyesa PYTHON REGEX -- ( ) [ ] . * + ? | are metacharacters, so escape them for literal text: `\.pipe\(` not `.pipe(`. A pattern with no metacharacters is just a substring. If it doesn't compile the searc…

No output schema declared.

No examples provided.

call_tree ~212

The TRANSITIVE call closure from one function, which get_callers (one hop) and trace_path (two endpoints) can't give. "direction": "forward" = everything this transitively CALLS (what does this route actually touch?); "reverse" = everything that transitively calls it (blast radius before a change). Each node carries "depth" (hops out) and a "leaf" flag where the chain ends. Proven edges only unless include_candidates also follows the speculative tier, whose nodes come back tagged "via":"candidate". Cycle-safe and capped -- a truncated closure says so.

NameTypeReqDescription
directionstringyesforward = what it transitively calls (reachability); reverse = what transitively calls it (blast radius)
include_candidatesboolean–optional: also follow speculative edges -- same-named ambiguity AND dynamic-dispatch candidates (an override reachable because its base method is called); such nodes come back tagged via:candidate (d…
name_or_idstringyes–

No output schema declared.

No examples provided.

forwardflow ~149

I changed what this returns -- who consumes it, and how far does it reach? The MIRROR of backflow, in TWO tiers. TIER 1: for every proven caller, the variable that CATCHES the return (`data = load()`) or an inline use. TIER 2: each caught value walked FORWARD -- passed on as an argument (landing on a named callee parameter), stored in a self.x field, or returned onward up the call graph -- to where it LANDS or an honest wall; depth-capped, exact or stopped, never a guess. Same best-effort binding as backflow/trace_path.

NameTypeReqDescription
name_or_idstringyes–

No output schema declared.

No examples provided.

get_callers ~133

Every function that calls X -- the reverse direction a body's own outline can't show. Dynamic dispatch is covered honestly: an override also gets "possible_callers_via_dispatch" (callers of the base method whose call can land here at runtime -- possible, not proven), and a method with overrides gets "overridden_by" (its callers may dispatch there instead). Treat both as blast radius. This is half of it; the other half -- who HOLDS X without calling it (registries, callbacks, aliases) -- is "referenced_by" on get_definition.

NameTypeReqDescription
name_or_idstringyes–

No output schema declared.

No examples provided.

get_definition ~192

The declaration card -- what a symbol IS: file, line span, parent, children, signature verbatim (defaults, annotations, splats), return type, decorators (@app.route, [HttpGet] -- evidence of how it gets invoked), base classes, docstring, and "fields" (for a struct/enum the fields ARE the meaning). A module adds its imports and which resolve in-repo. Constants and VARIABLES get a binding card: the ordered assignment sequence, every line the value could have changed, each rhs classified. "called_by" is who PROVENLY calls this, with a count; "referenced_by" is who HOLDS or reads it WITHOUT calling -- attribute reads, registry values, Thread(target=...) wiring, aliases -- the half of blast radius get_callers can't see. Body: skim_source. Raw text: read_source.

NameTypeReqDescription
name_or_idstringyes–

No output schema declared.

No examples provided.

get_hierarchy ~120

The class TREE for a type: resolved BASES (up) and direct SUBCLASSES (down) -- inheritance the compiler resolved at build time, which get_definition shows only as raw `extends` text. Returns "bases" (direct), "ancestry" (the whole chain, nearest first), "subclasses" (direct), each subclass tagged with the methods it OVERRIDES here and whether it has subclasses of its own. In-repo relations only (an external base like Thread won't appear).

NameTypeReqDescription
name_or_idstringyes–

No output schema declared.

No examples provided.

list_dependencies ~264

The LIBRARY surface, deduped to library roots with usage counts (`numpy.array`/`numpy.mean` both roll into one `numpy` entry) -- "third_party": external code leaned on but not owned, plus the raw import statements behind that evidence. OMIT name_or_id for THE WHOLE REPO; pass a file path or a scope id (function/class) to scope the same dedup to just that target. The always-deduped-roots view -- for raw call SITES (name/args/line) at any of the same granularities, use list_external_calls instead. A separate `unresolved_imports` field (sibling to third_party, NOT inside it) lists imports whose own syntax already proves in-repo intent (a relative import, require_relative, a quoted #include, rust's use crate/self/super) but still failed to resolve to a file -- a compiler gap, never counted as a dependency. Aggregated from references; no vendored code is parsed. Non-code repo files are list_unlisted_files, calls the compiler couldn't classify are list_unresolved_calls.

NameTypeReqDescription
name_or_idstring–a repo-relative file path or a scope id (function/class); omit entirely for the whole repo

No output schema declared.

No examples provided.

list_external_calls ~280

A FILE's, a SCOPE's, or (name_or_id omitted) THE WHOLE REPO's EXTERNAL (stdlib/third-party) call SITES, each with raw arguments and line -- the calls a skim shows WITHOUT a → . profile flattens these to bare names and drops args/lines. A class returns the union across its methods, a file the union across every scope in it, no argument the union across the whole repo (capped -- narrow to a file/scope for the rest, or use list_dependencies for the already-deduped library-roots-with-counts view instead of raw sites). Each entry tagged with which file/scope makes the call. Entries of kind "unresolved" are the honest can't-settle case: `reason` names the wall -- opaque_receiver / untyped_local (no target named) or name_collision / linkage_refused (2+ real in-repo targets in `candidates`, no evidence to choose; NOT library calls) -- and `supposed` holds the raw text as scope::name, a lead, not a verified id. list_unresolved_calls collects these too; get_callers is the in-repo direction.

NameTypeReqDescription
name_or_idstring–a repo-relative file path or a scope id (function/class); omit entirely for the whole repo

No output schema declared.

No examples provided.

list_files ~171

ONE directory level of the map (like `ls`, not `ls -R`). Returns {dir, files, subdirs}: `files` are the analyzed files DIRECTLY in `path`, each with language, line count, docstring, top-level symbols (id + kind + line -- every id is accepted by every other tool) and constant names; `subdirs` are the immediate folders, each with a recursive file count so you see where the code mass is. Omit `path` for the root, then drill with list_files("src/foo"). This is the project's OWN code; libraries are list_dependencies, non-code files list_unlisted_files.

NameTypeReqDescription
pathstring–a directory to open, project-root-relative (e.g. "src/parser"); omit or "" for the root

No output schema declared.

No examples provided.

list_unlisted_files ~180

Repo files the map does NOT index, each with its reason: "no_grammar" (non-code assets -- images, data, configs, docs, lockfiles -- and any language without a grammar), "data_blob" (supported extension skipped as minified/base64), "parse_error" (a supported file that crashed analysis -- a defect worth flagging), "not_downloaded" (hosted demo only: listed by GitHub's tree, never fetched). Also excluded_dirs, the directories the walk deliberately skipped (vendored/build/VCS), so absence is never silent. Repo-relative paths: read_source opens any of these, and your own grep searches them -- benzi_grep does NOT, it only sees indexed files. An unlisted schema.sql, fixture json, or a whole language without a grammar can still hold the answer.

Input schema present but exposes no named parameters.

No output schema declared.

No examples provided.

list_unresolved_calls ~256

Call sites the compiler SAW but could not settle -- neither in-repo nor provably a library call. Each carries `supposed` (raw call text as a scope::name id, `ax::plot` -- a lead, NOT a verified symbol) and `reason`: "opaque_receiver" (receiver expression dropped -- a nested call's result, a dereferenced pointer) or "untyped_local" (known name, type never inferred -- a parameter's .method(), a called function pointer), neither naming a target; or "name_collision" / "linkage_refused", which DID name 2+ real in-repo targets in `candidates` with no evidence to choose -- worth reading, not a dead end. OMIT name_or_id for THE WHOLE REPO (per-file counts, where the dark mass sits); pass a file path or a scope id (a function/class) for that target's entries with lines. Distinct from candidate_edges (dynamic dispatch, unresolvable statically) and list_dependencies (library evidence exists).

NameTypeReqDescription
name_or_idstring–a repo-relative file path or a scope id (function/class); omit entirely for the whole-repo per-file summary

No output schema declared.

No examples provided.

markup_find_anchor ~83

Fuzzy-find an ANCHOR by name -- a handle the UI hangs on: id (#tree-panel), class (.panel), or tag. Each hit shows its declare/style/grab tallies. Turns 'the left panel' into a handle for markup_get_definition.

NameTypeReqDescription
querystringyeshandle name or partial (e.g. 'tree', '.row')

No output schema declared.

No examples provided.

markup_get_definition ~163

The anchor card: where a handle is DECLARED (html element), STYLED (css rules + values + any @media), and GRABBED (js lookups), each with a layer-tagged uid (html::/css::/js::file:line). Those three lists ARE the blast radius. An id handle also gets `effective`: the WINNING rule per property (specificity + source order) as {prop:{uid,value}} -- to restyle, edit effective[prop].uid, since editing a non-winning styled rule does nothing on screen. Universal/@media/state/context rules appear in styled but aren't resolved into the winner.

NameTypeReqDescription
name_or_idstringyesa handle: name, #id, .class, or [attr]

No output schema declared.

No examples provided.

markup_list_files ~39

Markup-engine orientation: which files carry UI (HTML/CSS/JS, embedded or standalone) and how much, plus the total anchor count.

Input schema present but exposes no named parameters.

No output schema declared.

No examples provided.

profile ~96

The full 360 on one symbol in ONE call -- its declaration (what it IS), the functions it calls + data it defines (what it DOES), who CALLS it + who HOLDS it (the full blast radius), and what each parameter is passed one hop back (what FEEDS it). Deeper on any dimension: skim_source, backflow, get_callers, read_source.

NameTypeReqDescription
name_or_idstringyes–

No output schema declared.

No examples provided.

read_reference ~151

Read one of Benzi's reference topics in full -- detail kept out of your system prompt so you only load what a job needs. Topics: "artifact" (how the map fits together -- call flow vs data flow and where they join, the symbol kinds, the UID-keyed tables the tools query), "uids" (the UID scheme, code and markup alphabets, the C/C++ declaration-vs-definition wrinkle), "languages" (how deep the map goes per language, and where an empty result means 'not indexed' rather than 'nothing uses it'), "markup" (anchors, the three layers, the cascade, its tools).

NameTypeReqDescription
topicstringyeswhich reference topic to read

No output schema declared.

No examples provided.

read_source ~142

The symbol's ACTUAL source, sliced to the exact span the map knows -- full fidelity: control flow, values, comments as written. Use when the answer hinges on real code ('what threshold', 'which branch'). Read the narrowest symbol that answers; start_line/end_line (absolute, the same lines skims/edges/callers report) fetch a window of a long body. Oversized spans truncate with a note.

NameTypeReqDescription
end_lineinteger–optional: last line to read (absolute file line number)
name_or_idstringyes–
start_lineinteger–optional: first line to read (absolute file line number)

No output schema declared.

No examples provided.

search_symbols ~154

Turn a half-remembered NAME into the UIDs every other tool takes. Fuzzy case-insensitive SUBSTRING match over every symbol including nested methods ('pack' finds _skyline_pack, build_pack) AND every BINDING: function locals and class-body data (symbolKind "Binding", with its defining line and value). Each hit carries `id`, `symbolKind`, `path`, `line_span` and caller/reference counts, so you can usually tell which one you meant without a follow-up get_definition. Takes a LIST of names to resolve in one call.

NameTypeReqDescription
querystring|arrayyesA name (or partial name) to search for, or a list of names to resolve in one call

No output schema declared.

No examples provided.

skim_source ~234

Reach for this FIRST when you need to know what a body does; it tells you which lines are worth read_source. A one-level outline: calls (with the raw arguments at each site), assignments, return/yield/raise, LOOP exits (break/continue, with their label where they carry one -- so you can see whether a loop runs to completion), and condition headers verbatim (`if not data:`, `for row in cursor:`) -- in source order, line-numbered, INDENTED to mirror real nesting. A leading → marks a call landing in THIS codebase; skim that id to descend one level, no → means external. A class returns "members" instead (its calls live in its methods); a file returns both. It omits the computation BETWEEN these lines (arithmetic, expression bodies, comments). Long outlines page at 40 steps; a truncated tail names the offset for the next page.

NameTypeReqDescription
name_or_idstringyes–
offsetinteger–optional: skip this many steps (for paging long outlines; a truncated page tells you the offset to use)

No output schema declared.

No examples provided.

trace_path ~158

The call chain between two functions AND the data along it: each hop's call site (line + raw args) plus "binds", those args zipped to the callee's parameter names, so renames read step to step (`req.body` enters `validate` as `payload`). No direction argument -- it searches both ways and reports which in "direction": forward, reverse (hops still in real call order), or undirected (shared intermediates only -- noted, not a flow). RESOLVED sites only: a value stashed in a field or passed through an untraced method call won't appear; read_source that hop.

NameTypeReqDescription
from_name_or_idstringyes–
to_name_or_idstringyes–

No output schema declared.

No examples provided.

Install

How do I install the Benzi MCP server?

Benzi runs locally as a PyPI package, launched with uvx benzi-mcp. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

pypi · benzi-mcp

# add to Claude Code
claude mcp add net-varianttech-benzi -- uvx benzi-mcp
Common questions

What is the Benzi MCP server?

Benzi is an MCP server listed in the public MCP registry as net.varianttech/benzi. Compiler-backed code intelligence: calls, data flow, references and class hierarchy as tools. This page covers its PyPI package (benzi-mcp).

Is the Benzi MCP server safe to use?

Benzi scores 69 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 17 October 2026. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

What tools does the Benzi MCP server expose?

Benzi exposes 21 tools: read_reference, list_files, list_dependencies, list_unlisted_files, list_unresolved_calls, and 16 more. Their descriptions and schemas cost roughly 3,759 tokens of context every time the server is loaded.

Is the Benzi MCP server still maintained?

Benzi is still listed as active in the MCP registry. We last reached this channel on 17 October 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.

What licence is the Benzi MCP server under?

Benzi declares the Proprietary licence, which is not on the OSI-approved list. Read the terms before using it at work, and note this covers the source only, not the cost of any service it calls.