Enola – MCP Architectural Snapshot Server and Knowledge Graph Enola Labs released enola, a local Model Context Protocol server that builds a deterministic architectural graph of codebases from source code for AI coding agents. The tool extracts precise structural models — modules, types, routes, dependencies — across 16+ languages and frameworks, eliminating guesswork and reducing token waste in AI-assisted development. enola runs as a pipeline that resolves syntax trees into a queryable cross-file, cross-repo graph, supporting agents like Claude Code, Cursor, and GitHub Copilot. A deterministic structural model of your codebase for AI coding agents — your real architecture, extracted from source, not guessed. enola is a local Model Context Protocol MCP https://modelcontextprotocol.io/ server. Point it at one or more repositories and it builds a precise graph of your code's architecture — modules, types, routes, dependencies, and how they all connect — straight from your source. It then exposes tools your AI agent can use to read, traverse, query, and reason over that structure. So before your agent writes a line of code, it already knows the shape of the thing it's editing. 1. Install curl -fsSL https://raw.githubusercontent.com/enola-labs/enola/main/install.sh | sh export PATH="$HOME/.local/bin:$PATH" if not already on PATH 2. Connect to your agent Claude Code: claude mcp add enola enola Cursor add to mcp.json : { "mcpServers": { "enola": { "command": "enola" } } } GitHub Copilot / VS Code add to .vscode/mcp.json : { "servers": { "enola": { "command": "enola" } } } 3. Ask it to map your project "Generate an architectural snapshot of /path/to/my/project" Done. Your agent now has a precise structural map of your code. For configuration options, multi-repo setup, and what to ask next, see Quick start quick-start below. Supported languages: Go · JavaScript · TypeScript · Python · Java · Kotlin · Swift · Ruby · Rust · C · C++ · PHP · Vue · Svelte · OpenAPI · gRPC — with framework awareness Next.js, Nuxt, SvelteKit, FastAPI, Django, Spring, Rails, Laravel, Symfony, SwiftUI, Jetpack Compose, WordPress, Kafka, … AI coding agents are powerful, but they're non-deterministic. On every task they re-discover your codebase from scratch — grepping, opening files, inferring how things fit together — and they get it subtly wrong often enough to matter. That guessing costs you time wrong turns, re-prompts and tokens re-reading the same files, every session . enola removes the guessing from the part that should never be guessed: the structure. It gives your agent a deterministic structural model — a structural architecture graph of your code's real types and relationships, built by parsers and graph algorithms, not by a language model. The structure is extracted from your source, not summarized from it; these are facts, not notes. Run it twice on the same commit and you get the same answer, every run. The agent starts from facts instead of assumptions. The result is the difference between vibe coding — prompt, hope, fix — and AI-augmented engineering : fewer wrong turns, fewer tokens burned, and work you can reproduce. enola adds determinism where AI lacks it, and your agent spends its intelligence on the actual problem instead of re-learning your repo. enola is a first step, not a replacement. It runsbeforeyour agent explores, so it knows where to look and what connects to what. It doesn't replace grep, file reading, or code search — it makes them precise. Fair question — plenty of tools parse an AST. enola does too. But parsing is the entry point , not the product: it's stage 2 of an 8-stage pipeline ARCHITECTURE.md → The pipeline /enola-labs/enola/blob/main/ARCHITECTURE.md the-pipeline . A tree-sitter grammar or an LSP hands you a syntax tree per file; enola treats that as raw material and resolves it into a queryable graph across your whole system. | A plain AST / tree-sitter / LSP tool gives you… | enola gives you… | |---|---| | a syntax tree, one file at a time | a typed, directed graph resolved across files, languages, and repos | foo.bar as a call to an unknown token | foo.bar resolved to the exact declaring symbol — through dispatch, inheritance, and imports | | edges exactly as written in source | edges made semantically complete — synthetic has method , module→import bridges, cross-repo links | | "find where this text appears" | "what transitively depends on this?" — answered by graph traversal, with accurate totals | | no way to tell a leaf from a blind spot | a genuine leaf service told apart from a coverage gap | | text you re-grep and re-infer every session | a byte-identical, content-fingerprinted snapshot | The gap a parser can't cross is resolution . A parser sees foo.bar as tokens; enola resolves it to the symbol that actually declares bar , across every dispatch mechanism real code uses — Ruby send / public send , Swift inherited-method chains, Kotlin callable references, Python absolute-import call edges, Java fully-qualified-name indexing — and then links per-repo graphs so a web client's HTTP or gRPC call resolves all the way to the backend route that serves it. That's why traverse , impact analysis , and find path return the exact dependent set instead of grep hits: the graph builder adds edges to make traversals "semantically complete rather than literally what each parser emitted." And it holds itself to that standard. enola reproduces its output to the byte — the snapshot ID is a content fingerprint, not a random UUID — and a large share of its engineering goes into catching what a naive parser gets subtly wrong: two apps that merely name the same type aren't fused into a false dependency, and a service with unresolved outbound calls is reported as a coverage gap, not a phantom leaf. The graph is derived, never guessed ; run it twice on the same commit and it's identical, byte for byte ARCHITECTURE.md → Determinism /enola-labs/enola/blob/main/ARCHITECTURE.md determinism--incremental-updates . Under the hood, enola models your codebase as a graph of architectural types — which we call kinds — and the relations between them. That's the whole concept: not a magic "knowledge graph," just a deeply technical, structural model of what your code actually contains. The kinds the nodes : module — a package or directory symbol — a function, method, struct, interface, type, class, or constant route — an HTTP/API endpoint storage — a database table, data store, or messaging topic dependency — an import relationship service — a whole repository used when you analyze several at once The relations the edges connect them: declares , imports , calls , implements , depends on , and more. Because the edges are typed and directed, the graph is queryable , not merely searchable — you compute over it. On top of it, enola builds a small set of tools your agent can call to answer real structural questions with exact answers. Getting to that graph is where the pipeline earns its keep. AST parsing is one stage; the rest is what makes the result queryable: parse → normalize into the typed fact model → link across repos with 2+ loaded → build a bidirectional graph index with synthetic edges → run deterministic explainers → emit a provenance receipt ARCHITECTURE.md → The pipeline /enola-labs/enola/blob/main/ARCHITECTURE.md the-pipeline . The explainers are real graph algorithms, not regex heuristics — Tarjan's SCC for dependency cycles, cycle-safe longest-path for dependency depth, statistical mean + 2σ outlier tests for god-classes, hotspots, and complexity — and each finding carries a confidence score, where 1.0 means a structural fact and anything below is a flagged heuristic ARCHITECTURE.md → Insights explainers /enola-labs/enola/blob/main/ARCHITECTURE.md insights-explainers . For the full mental model and internals, see ARCHITECTURE.md . Everyone above the keyboard needs the same thing enola produces: a structural map of the system that's actually correct . Because the graph is deterministic and derived from source, an agent can turn it into an always-accurate architecture diagram on demand — a mermaid module graph, a cross-repo dependency map — and it matches the code every time, and again next quarter, byte for byte. enola doesn't draw the diagram; it hands your agent the facts to draw it from, so the picture is never the stale one on the wiki. Developers pairing with an AI coding agent — Claude Code, Cursor, Copilot, Opencode, or any MCP-compatible tool. The agent starts from your real structure instead of re-guessing it every task. Teams working across multiple repos — a backend, a web frontend, a mobile app. enola links them into one cross-repo graph so an agent can follow a call from the web client all the way into the service that answers it — including the asynchronous hop a call graph can't see, where one service consumes the Kafka events another produces. And because that's a real graph rather than a fixed set of features, questions you'd otherwise reach for a dedicated tool to answer become plain queries over it — which of the backend's endpoints does no client app call? among them, a cleanup shortlist derived from the same client→server links verify against callers outside the snapshot — cron jobs, webhooks, third-party consumers — before deleting . Anyone about to refactor — and wanting to know the blast radius before touching code. Architects — the structural view you usually maintain by hand, computed from the code instead of a diagram that drifts out of date: dependency cycles, layer violations, call-graph hotspots, cross-repo coupling, and dependency depth — plus a module/dependency diagram an agent regenerates from the current commit, so the picture stays honest. Engineering leaders — CTOs, VPs, and managers — a trustworthy picture of a codebase's shape for planning, onboarding, and risk. Deterministic signals cycles, hotspots, coupling instead of gut feel, a new-hire tour or a deck diagram that matches reality, and a map that's reproducible run to run — so two people looking at it see the same thing. The workflow is simple: generate the snapshot once, then ask. These aren't text lookups — each tool computes over the graph : traverse walks reachability, find path finds the shortest chain between two points, impact analysis takes the transitive reverse closure. After the snapshot, your agent has these tools on top of the graph: | Tool | The question it answers | |---|---| generate snapshot | "Snapshot this repo." Build or refresh the graph. Run it first; use append to add more repos. | explore | "What's in this module/file/symbol, and what touches it?" A guided tour. | query facts | "List exactly these." Every route, every interface, every external dependency. | query insights | "What did the analysis find?" Fetch the computed findings — unused routes, cycles, god-classes — instead of re-deriving them. | show symbol | "Show me the code." Jump straight to a symbol's source. | traverse | "What does X depend on?" / "What depends on X?" Walk the graph. | find path | "How does A reach B?" The call or dependency chain between two points. | impact analysis | "If I change X, what breaks?" The blast radius of a change. | coverage report | "Which cross-repo edges did enola resolve vs. miss?" Tell a genuine leaf service from a coverage gap. | set baseline | "Remember the architecture as it is now." Pin a baseline before you start editing. | diff snapshot | "What did my change actually do?" The architectural delta vs. the baseline — new findings, new coupling, added/removed symbols. Warns if the two snapshots aren't comparable. | snapshot receipt | "What was this graph generated over, and how complete is it?" Provenance version, git ref + dirty, snapshot ID, output hashes plus extraction-quality metrics. | compare receipts | "Are these two snapshots even comparable?" A comparability verdict + metric deltas — the gate before trusting a diff, and a signal for improving coverage. | impact analysis is the one to know. Before a refactor, it computes the full set of code that transitively depends on what you're about to change — grouped by how many hops away it is, and aware of cross-repo dependencies. Instead of your agent guessing what a change might affect and missing things , it gets the exact dependent set. That's determinism turned into a concrete payoff: safer changes, planned in the right order, the first time. diff snapshot closes the loop on the edit itself. Where impact analysis plans a change, diff snapshot verifies it: pin a baseline set baseline , make your edits, re-snapshot, and ask what changed. It's a delta, not a linter — it reports only what moved findings that newly appeared or were resolved, new/removed coupling, added/removed symbols and stays silent about pre-existing state, so a pattern that was already there before and after never fires. Instead of re-reading files to confirm the agent built what it claimed, you get a deterministic answer: generate snapshot → set baseline → edit → generate snapshot → diff snapshot .See ARCHITECTURE.md for every tool's full parameters. The examples below ask different models to explain the authentication and authorization flow across three repositories — a web UI client, a backend, and a custom auth provider — using the enola snapshot as context. Grab a prebuilt binary — no Go toolchain or C compiler required: curl -fsSL https://raw.githubusercontent.com/enola-labs/enola/main/install.sh | sh This installs enola to ~/.local/bin . If that's not on your PATH , add it: export PATH="$HOME/.local/bin:$PATH" Binaries are published for Linux, macOS amd64/arm64 , and Windows amd64 . You can also download a specific build from the Releases page https://github.com/enola-labs/enola/releases , or build from source build-from-source . Once installed, update to the latest release in place: enola upgrade This downloads the newest build for your platform, verifies its checksum, and replaces the running binary. If enola is installed somewhere your user can't write, re-run with elevated permissions or re-run the install script above. Because your agent launches enola as a long-lived MCP server process, an upgrade only takes effect once that process restarts — reconnect the MCP server so it picks up the new binary: Claude Code — restart the session, or re-register with claude mcp remove enola && claude mcp add enola enola . Cursor — toggle the enola server off and back on in Settings → MCP or reload the window . GitHub Copilot VS Code — restart the server from the .vscode/mcp.json editor the Restart CodeLens above the server entry , or reload the window. enola needs no config file. Every setting has a built-in default, so out of the box it indexes the current repo with all extractors enabled and writes to .enola/ . A config file mcp-arch.yaml only overrides those defaults — it never adds capability you'd otherwise lack. When enola can't find one it simply prints warning: …, using defaults and carries on. The install script installs only the binary , by design — it does not place a config file. Grab the bundled one from the repo whenever you want to customize tune the ignore globs, pick a subset of extractors, change the output dir, … : curl -fsSL https://raw.githubusercontent.com/enola-labs/enola/main/mcp-arch.yaml -o mcp-arch.yaml The examples/ /enola-labs/enola/blob/main/examples directory has ready-made per-language and multi-repo starting points, and documents every option. For the full field reference and defaults, see /enola-labs/enola/blob/main/examples/full.yaml examples/full.yaml . ARCHITECTURE.md → Configuration /enola-labs/enola/blob/main/ARCHITECTURE.md configuration Claude Code — register enola as an MCP server with one command. This assumes the enola binary is on your PATH the install script above puts it in ~/.local/bin : claude mcp add enola enola The shape is claude mcp add