# najaeda/naja-scope [Health: Active]

**Category:** 📟 Embedded System  
**Repository:** https://github.com/najaeda/naja-scope  
**GitHub Stars:** 18  
**Views:** 1  
**Installs:** 0  
**Upvotes:** 0  
**Directory Page:** https://allmcps.com/mcp/najaeda-naja-scope

## Description
Lets AI agents explore elaborated SystemVerilog/Verilog designs (RTL or gate-level netlists) without pasting RTL into context: trace signal fan-in/fan-out, walk module hierarchy, and jump to exact file:line source, backed by the najaeda netlist engine.

## Tools
Capabilities this server exposes over MCP:

- **open_schematic** — Serve an interactive browser schematic of the current design. Returns a
    local URL to open on the MCP server's machine; requires the schematic extra.
    Uses the loaded design and supports anonymous #id instances.
- **annotate_schematic** — Replace schematic annotations on instances or pins/ports. Returns the
    local viewer URL and count. Annotations clear when the design changes.
- **get_schematic_selection** — Return the last browser-selected instance as a naja-scope path, or null.
    Use the returned path with module-card, source, or hierarchy tools.
- **status** — Inspect the current in-memory session without changing it. Use this
    before design queries to confirm a design is loaded and whether get_intent
    is live (`intent_loaded`) or can be reloaded (`intent_loadable`). Returns
    `loaded` and, when available, the top summary and loaded source files.
- **load_systemverilog** — Elaborate local SystemVerilog sources into the active design session.
    Use this for SystemVerilog RTL; use load_vhdl for VHDL (beta), or
    load_verilog with load_liberty/load_primitives for a
    structural gate netlist. Requires at least `files` or `flist` and changes
    the in-memory design session.
    Anonymous lowered objects are addressable by #<id>. defines are
    preprocessor -D entries ("NAME" or "NAME=VALUE"). allow_unknown_designs=True
    blackboxes any module still undefined instead of failing (e.g. undelivered
    hard macros in a partly-open-source design). blackbox_multi_writer_memories
    does the same for modules whose multi-writer memories naja cannot infer.
    intent=True retains naja's in-engine SNL↔slang link for get_intent.
- **load_verilog** — Load local gate-level or structural Verilog into the active session.
    First call load_liberty for Liberty cells or load_primitives for built-ins;
    use load_systemverilog instead for RTL elaboration. Unknown modules fail
    unless `allow_unknown_designs` is true. get_source shows the netlist
    declaration of an object; for Yosys output, yosys_source_attributes=True
    also records its RTL `origins` (get_source origin=N). get_intent cannot
    answer for netlists.
- **load_vhdl** — Load VHDL into the active session (beta, restricted two-state RTL subset).
    Prefer passing every file of the design as one list (any order; units are
    resolved across files). Single-file calls still work: load package files
    first, then the top. Package-only files or entities awaiting generics may
    return top=null.
    Use hierarchy, cards and connectivity queries on the elaborated design.
    SystemVerilog intent recovery is unavailable; source ranges are not
    guaranteed. Unsupported constructs may fail during beta development.
    Returns the top summary when elaborated, language and beta status.
- **load_liberty** — Register standard-cell models from local Liberty `.lib` files in the
    active session. Use this before load_verilog when a gate netlist instantiates
    those cells; use load_primitives instead for the built-in Xilinx or Yosys
    model sets. This changes session state and returns `{"ok": true}`.
- **load_primitives** — Register primitive models in the active session from either a built-in
    `name` (`xilinx` or `yosys`) or one local Python `file` defining `load(db)`.
    Provide one source; `name` takes precedence when both are set. A custom file
    executes unsandboxed Python in the server process, so only use trusted code.
    Use load_liberty instead for standard-cell `.lib` files. Returns
    `{"ok": true}`.
- **save_snapshot** — Write the active design and source metadata to a local directory for
    fast reload. Use after loading a design; load_snapshot reads the result.
    Existing snapshot files in the directory may be overwritten. Snapshots are
    tied to their producing najaeda version, and returns include the saved path.
- **load_snapshot** — Load a compatible save_snapshot directory into the active session in
    seconds instead of re-elaborating. Use load_systemverilog/load_verilog/load_vhdl when
    no compatible snapshot exists. The directory must match this najaeda version.
    intent=True also re-elaborates the warm intent layer from the flist saved in
    the snapshot (for get_intent).
- **reset_universe** — Discard the active design and all in-memory session state. Use before
    starting an unrelated design; do not use merely to inspect status. This is
    destructive to the current session but does not delete source or snapshots.
    Repeating it is safe and returns `{"ok": true}`.
- **resolve** — Resolve a known hierarchical object path to instance, term, or net
    descriptors with source references. The final segment accepts a glob and
    bit selects (for example `top.u_uart.tx_o[0]`). Use find when the path is
    unknown; use get_hierarchy to browse children. This read-only query requires
    a loaded design and returns did-you-mean suggestions on failure.
- **find** — Search case-sensitive object names across the loaded design with a glob.
    Use this when an exact path is unknown; use resolve once a path is known or
    get_hierarchy to browse structure. A dot in `pattern` switches matching to
    full hierarchical paths. Returns typed descriptors in `matches` plus
    `count`, `has_more`, and an opaque `next_cursor` for pagination.
- **get_hierarchy** — Browse the instance tree below `path` (or the top instance). Use this
    for structural children; use find for design-wide name search or get_stats
    for aggregate model counts. Lists only non-assign
    children (real submodules + leaf primitives); `assign` glue is reported as
    `assign_count`, not enumerated. Each child carries a `leaf` flag (submodule
    vs leaf primitive). depth<=5; the non-assign set is paginated at the root
    via limit/cursor (next_cursor/has_more), deeper levels via children_truncated.
- **get_drivers** — List the immediate upstream endpoints that drive a term or net across
    hierarchy. Use this for direct sources; use get_loads for downstream readers
    or trace_cone for the transitive combinational fanin. Returns leaf drivers
    (FF/gate instances with pin, model, source ref) and top-level ports.
    Lowered assign glue is traversed rather than reported as an endpoint.
    Literal assign drivers include `constant` (0, 1, X, or Z); bus entries
    include the driven `bit`.
    Capped at limit (default 50, max 200) with a `truncated` flag; no cursor —
    raise limit to see more.
- **get_loads** — List the immediate downstream endpoints that consume a term or net
    across hierarchy. Use this for direct readers; use get_drivers for upstream
    sources or trace_cone for the transitive combinational fanout. Returns leaf
    readers
    (instances with pin, model, source ref) and top-level ports. Lowered assign
    glue is traversed rather than reported as an endpoint.
    Capped at limit (default 50, max 200) with a `truncated` flag; no cursor —
    raise limit to see more.
- **trace_cone** — Trace the combinational fanin/fanout cone of a term/net via naja's
    LogicCone. Use this for transitive logic reachability; use get_drivers or
    get_loads for only immediate endpoints. direction: fanin|fanout. The cone
    crosses hierarchy and
    combinatorial arcs and always stops at flops, top ports, and opaque
    black-box cells. Returns node_count, counts_by_kind, counts_by_model, and a
    `frontier` of {flops, ports, blackboxes} with exact counts and lists capped
    at max_frontier (<=200) with a truncation marker.
    `cross_hierarchy` groups the flop frontier by top-level submodule and, under
    outside_root_subtree, names the frontier registers that live OUTSIDE the
    cone root's own subtree (the cross-hierarchy answer) — read it directly.
- **get_source** — Read the bounded source excerpt that produced an object (for example,
    an SV FF instance maps to its `always_ff` block; a netlist cell maps to its
    instantiation line). Use when exact source text is needed; use get_intent
    for typedef/enum/parameter semantics. When the response lists `origins`
    (e.g. Yosys src attributes), call again with origin=N to read that RTL.
    Returns object, file, start/end range, text, and truncation status without
    modifying files; missing paths and source ranges return structured errors.
- **get_module_card** — Deterministic module summary: ports, instance counts by model,
    sequential cell and register-bit counts, bounded RAM/ROM details (width,
    depth, ports, initialization preview), and source ref. Clock/reset candidates
    are name-based guesses; verify before relying on them. Use this
    for one model's interface; use get_stats for counts below an instance.
- **get_stats** — Summarize instance population by model below `path` or the top design.
    Use this for aggregate leaf/sequential/model counts, register bits, and
    RAM/ROM counts and capacity; use get_hierarchy for actual child instances
    or get_module_card for one model's ports. This
    read-only query requires a loaded design. Returns `root_model`, flat totals,
    a paginated `models` list, `total_models`, `has_more`, and `next_cursor`.
    Register bits count modeled flip-flop/latch states, excluding memories;
    unknown sequential bit counts are reported separately.
- **get_intent** — Retrieve source-level intent that netlist lowering erases (warm-only).
    Use when the answer is in the SystemVerilog *type/declaration*, not the
    flattened gates: enum/typedef state names + encodings (incl. PACKAGE
    typedefs whose members live in another file), and symbolic PARAMETER
    expressions (the formula behind a baked-in width).
    ref: a hierarchical path ('cva6.csr_regfile_i.priv_lvl_q'), a package member
    ('riscv::PLEN'), or an instance path for its parameters.
    want: auto | type | fsm_states | parameters. If the intent layer is not
    loaded, returns a note and you should fall back to get_source.
- **load_intent** — Make the warm source-intent layer available for get_intent. Use after a
    SystemVerilog load that did not retain intent; do not call for VHDL or gate-level
    Verilog, and prefer `load_systemverilog(intent=True)` on the initial load.
    This is a no-op when the link is already live; otherwise it replaces the
    active universe by re-elaborating from explicit or captured `flist`/`files`.
    Returns `intent_loaded`; missing inputs produce a structured error.

## Claude Desktop Quick Installation
Install path detected from listing signals. Uses `uvx` (confidence: high):

```json
"mcpServers": {
  "naja-scope": {
    "command": "uvx",
    "args": ["naja-scope"]
  }
}
```

## Documentation

## What najaeda/naja-scope MCP server does

The najaeda/naja-scope MCP server gives an AI assistant a navigable representation of an elaborated hardware design instead of requiring the design source to be pasted into the conversation. It is intended for SystemVerilog RTL, structural Verilog produced after synthesis, and a restricted beta subset of VHDL.

The server can expose module and instance hierarchy, ports, signal connectivity, lowered primitives, and source references. Responses include file-and-line ranges where available, helping an agent connect a structural answer back to the relevant source. Results are bounded: lists paginate and large responses include truncation markers.

## How it works

Install the Python package and run the `naja-scope-mcp` executable as an MCP server. An agent first loads a design and then issues focused queries against the in-memory elaborated representation. This avoids repeatedly reading source files and is useful for questions such as which logic drives a signal, what a module contains, or which instances load a net.

The najaeda/naja-scope MCP server uses the najaeda netlist engine. For gate-level work, load the structural netlist together with the Liberty library describing its standard cells. Yosys source attributes can optionally preserve links from netlist locations back to RTL origins.

## Setup and configuration

Install from PyPI with:

```sh
pip install naja-scope
```

For a standard input/output connection, start `naja-scope-mcp` and register that executable with the MCP client. Claude Code can be configured with:

```sh
claude mcp add naja-scope -- naja-scope-mcp
```

The server also supports Streamable HTTP. Run it with `--transport streamable-http`, optionally setting `--host` and `--port`; the MCP endpoint is served at `/mcp`.

## Tools and capabilities

The documented operations include:

- Loading SystemVerilog designs and selecting a top module.
- Loading VHDL files with `load_vhdl`; package files may need to be loaded before the top file.
- Traversing modules, instances, ports, and hierarchy.
- Finding signal drivers and loads across module boundaries.
- Tracing combinational fan-in and fan-out cones until register boundaries.
- Locating nets and cells with `get_source`, including optional RTL origins from Yosys attributes.
- Summarizing module contents with `get_module_card`, including direct-child registers and inferred RAM or ROM details.
- Aggregating design statistics with `get_stats`, including flattened register and memory counts.
- Recovering design information such as enum states, struct or union fields, and parameter formulas when available from elaboration.

## Limitations and notes

The najaeda/naja-scope MCP server does not replace textual source search for local questions that are directly answered by file contents. VHDL support is beta, covers a restricted two-state RTL subset, and does not guarantee source ranges; intent operations remain SystemVerilog-only.

Memory summaries apply to recognized native naja primitives. Opaque memory macros do not receive inferred capacity, and unknown sequential-cell state models are reported separately from known register-bit counts. Logic cones on gate-level designs stop at sequential cells. The HTTP transport has no built-in authentication, and the documented benchmark results should be treated as results for the described CVA6 setup rather than a general performance guarantee.

_Full upstream README: https://allmcps.com/mcp/najaeda-naja-scope/readme_

