Skip to main content
Glama
EdgeHop

EdgeHop

by EdgeHop

EdgeHop builds an accurate, durable graph of the symbols in a solution — and the relationships between them — then serves it to an AI assistant over the Model Context Protocol (MCP). It doesn't match text; it understands code. Every relationship is resolved from the compiler's own semantic model, so a call, an implementation, or a reference is the actual one the compiler binds — not a name that happens to look alike. Instead of guessing at call chains from text search, your assistant asks "who calls this method?", "what implements this interface?", or "what breaks if I change this?" and gets answers grounded in that semantic understanding — including across tier boundaries the compiler can't cross: the Web-to-API HTTP call and the C#-to-JavaScript interop bridge.

Project types. EdgeHop is built .NET-first, but it is not limited to .NET. Any directory works as a target: a .sln/.csproj solution, a mixed C#+JS/TS Blazor app, or a pure HTML/JavaScript/TypeScript project with no .NET at all. Additional languages and project types are added through extractor plugins.


What it does

  • Indexes a .sln — or any project directory — into a code graph: C# symbols from Roslyn's semantic model, and JavaScript/TypeScript symbols from a native oxc parse — merged into one graph per git branch. .NET is the primary focus, but the target need not be a .NET project at all: point it at a pure HTML/JS/TS tree (no .sln, no Visual Studio, no .NET involved) and the oxc extractor graphs it while the Roslyn extractor simply no-ops.

  • Captures real relationships, not text matches: calls, interface implementations, inheritance, overrides, type references, containment, Blazor component rendering, and two cross-tier bridges — HTTP client-to-endpoint calls and bidirectional C#↔JS interop.

  • Serves the graph over MCP so an assistant (e.g. Claude Code) can traverse it with five focused tools, and over a plain CLI for scripting.

  • Stays current with your working tree via watch mode and optional git hooks that re-index in the background on commit, merge, and checkout — per branch, without touching your working directory.

Related MCP server: codebase-memory-mcp

Why it's different

Most "code intelligence for AI" tooling falls into one of two camps, and EdgeHop deliberately avoids both:

  • Text / Tree-sitter indexers parse syntax without resolving symbols. They can tell you a token named Save appears in twelve files; they can't tell you which Save a given call actually binds to. EdgeHop uses Roslyn's semantic model, so a CALLS edge is a resolved invocation, not a name collision — the difference between a guess and an answer.

  • Monolithic graph.json extractors (e.g. Graphify-style tools) dump the whole graph to a single file that must be regenerated wholesale on every change. EdgeHop stores the graph in an indexed, durable, incrementally-reconciled database and updates only what changed, so it scales and stays truthful as you work.

Beyond that, three things are unusual:

  • Cross-tier edges. Call chains stay walkable straight across boundaries a compiler can't cross:

    • Web tier → API. A Web-tier HttpClient call is linked to the C# method that serves the matching endpoint (by verb + route template).

    • C# ↔ JavaScript interop, both directions. IJSRuntime.InvokeAsync → the JS export it invokes, and JS DotNet.invoke* → the [JSInvokable] C# method it targets.

  • Branch-aware and local-first. The graph is scoped per git branch and lives entirely on your machine. No shared server, no credentials, no telemetry. Switch branches and the next query reflects it.

  • Pluggable storage and extractors. SQLite by default (embedded, zero-config), Neo4j optional. The C# and JS/TS extractors are independent, reflection-loaded plugins — the same seam is how support for other languages and project types will be added over time, without changing the core or the query surface.

Requirements

  • .NET 10 SDK/runtime

  • win-x64, linux-x64, or osx-arm64 — the only platform-specific dependency is the bundled edgehop-oxc JS/TS parser, a native binary shipped for those three platforms. Everything else is portable .NET. See Roadmap — a platform-independent oxc parser is planned, which will drop the native-binary requirement entirely.

  • No database or credentials for the default SQLite backend. Neo4j is opt-in.

Project types. EdgeHop is built .NET-first, but it is not limited to .NET. Any directory works as a target: a .sln/.csproj solution, a mixed C#+JS/TS Blazor app, or a pure HTML/JavaScript/TypeScript project with no .NET at all. Additional languages and project types are added through extractor plugins.

Installation

EdgeHop ships as a single .NET global tool:

dotnet tool install -g EdgeHop --prerelease
dotnet tool update  -g EdgeHop --prerelease   # later, to upgrade

Quick start

1. Index a solution (or a directory):

edgehop index C:\path\to\YourApp.sln

2. Query it from the CLI:

edgehop find-symbol OrderService
edgehop get-callers <symbolId> --depth 3
edgehop get-relationships <symbolId> --edge-type IMPLEMENTS
edgehop get-path <fromId> <toId>
edgehop stats

Add --json to any query verb for machine-readable output.

3. Wire it into your AI assistant — point an MCP client at the edgehop mcp command. For Claude Code, add to .mcp.json:

{
  "mcpServers": {
    "edgehop": {
      "command": "edgehop",
      "args": ["mcp"],
      "env": { "EDGEHOP_REPO": "C:\\path\\to\\your\\solution" }
    }
  }
}

4. Keep it fresh — watch mode, or install background git hooks:

edgehop index C:\path\to\YourApp.sln --watch
edgehop install-hooks C:\path\to\YourApp.sln   # re-index on commit / merge / checkout

What the graph captures

Node kinds: namespaces, types (class/struct/interface/enum), methods, properties, fields, Blazor components, and JS/TS functions.

Edge types:

type

meaning

CONTAINS

namespace → type, type → member

CALLS

method invocation (resolved via the semantic model)

IMPLEMENTS

class/struct implements interface

INHERITS

derived type → base type

OVERRIDES

override → overridden method

REFERENCES

a symbol uses a type (parameter, return, field type, …)

RENDERS

a Blazor component renders a child component in its markup

HTTP_CALLS

a Web-tier HttpClient call → the C# method serving that endpoint

JS_CALLS

C# IJSRuntime interop call → the JS function it invokes

JS_INVOKES

JS DotNet.invoke* → the [JSInvokable] C# method it targets

The MCP query surface

tool

answers

find_symbol

where a symbol lives; whether it's a component; which route it serves

get_callers

who calls a method, N hops deep — across HTTP and JS interop too

get_relationships

everything related to a symbol by any edge type; filter by direction/type

get_path

the shortest directed path between two symbols (reachability/impact)

graph_stats

per-branch totals, counts by kind and edge type, and the busiest nodes

Text and content search stays your assistant's grep job — EdgeHop indexes structure, not text.

Configuration

All configuration is environment variables (no config file, no stored credentials):

variable

purpose

EDGEHOP_BACKEND

sqlite (default) or neo4j

EDGEHOP_SQLITE_PATH

override the store file (default is derived per repo under %LOCALAPPDATA%\EdgeHop\stores\)

EDGEHOP_REPO

which repo's current branch the MCP server follows

EDGEHOP_BRANCH

force a branch (otherwise resolved from git)

EDGEHOP_EXTRACTORS

subset the loaded extractors (default: all)

EDGEHOP_JS_INTEROP

C#↔JS interop match mode: precise (default) / broad / off

NEO4J_URI etc.

Neo4j connection info, read only when EDGEHOP_BACKEND=neo4j

The SQLite store is per-solution and derived from the repo, so multiple solutions index side by side with zero configuration.

How it works

 C#/Razor ──▶ Roslyn extractor ─┐
                                 ├─▶ reconcile (per-branch diff) ─▶ graph store ─▶ MCP / CLI
 JS/TS ─────▶ oxc extractor  ────┘                                   (SQLite/Neo4j)

Extraction is whole-solution; storage is incremental — each index run reconciles the new graph against the stored one for that branch and applies only the difference. Stores and extractors are reflection-loaded plugins, so neither the core nor the host depends on a specific database driver or on MSBuild.

A worked example

The commands below run against the in-repo sample Blazor Server app at tests/samples/EdgeHopExplorer.BlazorServer — a small app whose Blazor UI calls a typed HttpClient that hits a minimal-API endpoint, so it exercises the cross-tier edges. First index it:

$ edgehop index tests/samples/EdgeHopExplorer.BlazorServer/EdgeHopExplorer.BlazorServer.sln
Extraction complete: 115 nodes, 168 edges.
oxc: 2 module(s)  11 nodes, 12 edges.
JS interop (precise): 2 C# call site(s), 3 JS export(s), 2 JS_CALLS edge(s).
DotNet interop (precise): 2 JS call site(s), 2 [JSInvokable] method(s), 2 JS_INVOKES edge(s).

1. Find a symbol — locate the Web-tier client method and its stable id:

$ edgehop find-symbol GetAllAsync
Method     Task<IReadOnlyList<FeatureInfo>> FeatureApiClient.GetAllAsync()
           id:  Method:System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<EdgeHopExplorer.BlazorServer.Domain.FeatureInfo>> EdgeHopExplorer.BlazorServer.Services.FeatureApiClient.GetAllAsync()
           doc: Services/FeatureApiClient.cs

1 match on branch 'main'.

2. Look up its relationships — what does this method reach? Note the HTTP_CALLS edge: EdgeHop resolved this client call to the minimal-API method that serves the matching route, across a tier boundary the compiler can't cross:

$ edgehop get-relationships "Method:...FeatureApiClient.GetAllAsync()" --direction out

HTTP_CALLS out
Method     IEndpointRouteBuilder FeatureEndpoints.MapFeatureEndpoints(IEndpointRouteBuilder app)
           id:  Method:...EdgeHopExplorer.BlazorServer.Endpoints.FeatureEndpoints.MapFeatureEndpoints(...)
           doc: Endpoints/FeatureEndpoints.cs
           routes: GET /api/features/all, GET /api/features/{name}, POST /api/features/search

REFERENCES out
NamedType  FeatureInfo
           id:  NamedType:EdgeHopExplorer.BlazorServer.Domain.FeatureInfo
           doc: Domain/FeatureInfo.cs

2 relationships on branch 'main'.

3. Find a path from one call to another — trace how the Blazor page's init handler reaches the API endpoint. The shortest directed path walks a CALLS edge and then the cross-tier HTTP_CALLS edge in a single traversal:

$ edgehop get-path "Method:...Features.OnInitializedAsync()" "Method:...FeatureEndpoints.MapFeatureEndpoints(...)"
Path ... (2 hops):

Task Features.OnInitializedAsync() --CALLS--> Task<IReadOnlyList<FeatureInfo>> FeatureApiClient.GetAllAsync() --HTTP_CALLS--> IEndpointRouteBuilder FeatureEndpoints.MapFeatureEndpoints(IEndpointRouteBuilder app)

That's a Blazor UI handler → typed HTTP client → API endpoint chain, reconstructed from the graph rather than guessed from text.

4. See which routes that endpoint serves — the path lands on the minimal-API method; inspect it and EdgeHop reports the concrete, verb-prefixed HTTP routes it registers, so the trace ends at the actual URLs the UI ultimately reaches:

$ edgehop find-symbol MapFeatureEndpoints
Method     IEndpointRouteBuilder FeatureEndpoints.MapFeatureEndpoints(IEndpointRouteBuilder app)
           id:  Method:...EdgeHopExplorer.BlazorServer.Endpoints.FeatureEndpoints.MapFeatureEndpoints(...)
           doc: Endpoints/FeatureEndpoints.cs
           routes: GET /api/features/all, GET /api/features/{name}, POST /api/features/search

1 match on branch 'main'.

Add --json to any query verb for the exact MCP tool shape.

Roadmap

  • Platform-independent JS/TS parser. EdgeHop ships the native edgehop-oxc binary for win-x64, linux-x64, and osx-arm64 today. A cross-platform oxc parser is planned, which will drop the native-binary requirement entirely and let EdgeHop run anywhere .NET 10 does.

  • More extractor plugins. The reflection-loaded extractor seam is designed to grow beyond C# and JS/TS to additional languages and project types.

Contributing

Contributions are welcome — see CONTRIBUTING.md for how to build, test, and submit changes.

License

Licensed under the Apache License 2.0.

Built on oxc (JS/TS parsing) and Roslyn (C#/Razor analysis). Bundled third-party components and their licenses are listed in THIRD-PARTY-NOTICES.md.

Available Tools

2 tools
get_relationshipsA
Read-onlyIdempotent

Find symbols related to the given symbol by a graph edge, in either direction. Edge types are CONTAINS (a type/namespace holds a member), CALLS, IMPLEMENTS, INHERITS, REFERENCES, OVERRIDES, RENDERS (a component renders another), HTTP_CALLS (cross-tier HTTP client to endpoint), JS_CALLS (C# to JS interop) and JS_INVOKES (JS to C# interop). 'direction' is 'out' (edges FROM the symbol — default), 'in' (edges INTO it) or 'both'. Pass 'edgeType' to keep just one type. 'depth' 1-10 (default 1) walks transitively, but any depth above 1 REQUIRES a single 'edgeType' — multi-hop mixed-type traversal is not supported. Use find_symbol first to obtain the anchor's stable symbol id. The anchor itself is never included; each hit carries the edge type that reached it and the direction traversed. 'truncated' is true when the fan-out cap was hit (restrict with an edge type).

ParametersJSON Schema
NameRequiredDescriptionDefault
depthNoMaximum traversal depth, between 1 and 10. Default 1 (direct neighbors only). Any value above 1 requires a single edgeType.
edgeTypeNoOptional exact edge-type filter: CONTAINS, CALLS, IMPLEMENTS, INHERITS, REFERENCES, OVERRIDES, RENDERS, HTTP_CALLS, JS_CALLS or JS_INVOKES. Required when depth is above 1.
symbolIdYesStable symbol id of the anchor, exactly as returned by find_symbol (e.g. 'Method:string TinyFixture.Greeter.Greet(string)').
directionNoTraversal direction: 'out' (edges from the symbol — default), 'in' (edges into it) or 'both'.out

TDQS

A4.7/5.0
Behavior5/5

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

Annotations declare readOnlyHint and idempotentHint, but the description goes far beyond: it details edge type meanings, direction options, depth behavior with restrictions, and return characteristics (anchor excluded, each hit carries edge type and direction, truncated flag). This provides rich behavioral context that the annotations alone do not cover.

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

Conciseness4/5

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

The description is a single paragraph of about 6-7 sentences, front-loaded with the main purpose. Every sentence adds value, but the structure could be improved (e.g., using bullet points for edge types). It is reasonably concise given the complexity of the tool.

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 bears the full burden of explaining return values. It explicitly states that the anchor is not included, each hit carries edge type and direction, and includes the truncated flag. Combined with the detailed parameter explanations, this makes the tool well-understood without an output schema.

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

Parameters5/5

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

The schema already covers all 4 parameters with descriptions (100% coverage). The description adds significant value by explaining the semantics of edge types in context, the meaning of direction values, the depth restriction logic, and the return behavior. It transforms raw parameters into actionable knowledge.

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?

The description clearly states the tool finds related symbols via graph edges, enumerates all edge types, and distinguishes parameters. It sets expectations for what the tool does (retrieve relationships) versus the sibling 'graph_stats' which presumably provides statistics. This is a specific verb+resource with clear scope.

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?

The description provides explicit usage guidance: use find_symbol first to get the symbolId, and notes that depth >1 requires a single edgeType. However, it does not explicitly contrast with the sibling tool 'graph_stats' or state when not to use this tool. The guidance is strong for prerequisites and constraints, but lacks explicit alternatives.

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

graph_statsA
Read-onlyIdempotent

Summarize the current branch's graph for orientation: total node and edge counts, node counts by kind, edge counts by type, and the top 'topN' god nodes (the highest-degree symbols). God-node degree EXCLUDES CONTAINS edges, so containers like namespaces and types do not dominate — the ranking surfaces the genuinely most-connected members. 'topN' is 1-50 (default 10) and is clamped into range rather than rejected.

ParametersJSON Schema
NameRequiredDescriptionDefault
topNNoNumber of god nodes to return, between 1 and 50. Default 10. Out-of-range values are clamped.

TDQS

A4.1/5.0
Behavior4/5

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

Annotations already declare readOnlyHint and idempotentHint, so the agent knows it's safe. The description adds valuable behavioral details: god-node degree excludes CONTAINS edges, and topN is clamped, which goes beyond annotations without contradiction.

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

Conciseness5/5

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

The description is concise, well-structured, and front-loaded with purpose. Every sentence contributes meaning without redundancy.

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?

For a simple tool with one optional parameter and no output schema, the description is complete: it explains output contents, algorithmic nuance, and parameter behavior. Annotations cover safety.

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

Parameters3/5

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

Schema coverage is 100%, and the description repeats the parameter details already present in the input schema. It does not add new meaning beyond what the schema provides.

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?

The description clearly states the tool summarizes the current branch's graph with specific output: total node/edge counts, counts by kind/type, and top god nodes. It uses specific verbs and resources, and the sibling 'get_relationships' is distinct in purpose.

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

Usage Guidelines3/5

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

The description gives context ('for orientation') but does not explicitly state when to use this tool versus alternatives like 'get_relationships'. It implies use for overview but lacks explicit when-not-to-use guidance.

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

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 2 tool updatesv0.1.23-alpha
    • First observedget_relationships
    • First observedgraph_stats

TDQS

A4/5.0

Scored across 2 tools

Disambiguation5/5

The two tools have entirely distinct purposes: one for traversing graph relationships from a specific symbol, the other for summarizing the entire graph. No overlap or ambiguity.

Naming Consistency5/5

Both tool names follow a consistent snake_case pattern: 'get_relationships' and 'graph_stats'. The naming style is uniform and predictable.

Tool Count2/5

Only 2 tools for a graph server is too few. Typical use cases require symbol lookup, edge queries, and more, but here the critical 'find_symbol' tool is missing (only mentioned in description). The surface feels incomplete.

Completeness1/5

The server lacks fundamental tools like 'find_symbol' (mentioned but not provided), making it impossible to use 'get_relationships' without an external anchor. No create/update/delete operations exist, dead-ending agents.

Maintenance

ActivityStale
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    C
    maintenance
    Cross-repository code knowledge graph MCP server for Java, Kotlin, JavaScript, and TypeScript. Indexes source code into embedded KuzuDB via tree-sitter and exposes 30+ tools for call-flow tracing, multi-hop taint analysis (OWASP/CWE/PCI/STIG), entry-point reachability filtering, performance hotspot detection, and license compliance — without reading source files. 95% fewer tokens vs source-read
    33
    1
    MIT
  • A
    license
    B
    quality
    A
    maintenance
    High-performance code intelligence MCP server. Indexes codebases into a persistent knowledge graph — average repo in milliseconds. 159 languages, sub-ms queries, 99% fewer tokens. Single static binary, zero dependencies.
    17
    44,266
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Indexes a mono-repo into a knowledge graph and provides MCP tools to query code structure—packages, components, routes, HTTP calls—without file reads or grep round-trips.
    7
    22 npm
    MIT