---
title: "Why your AI assistant should query your architecture, not your files"
description: "File dumps and embeddings break down on large C# codebases. A semantic code graph gives an LLM the exact dependency paths a question needs — nothing more."
date: 2026-07-02
tags: [code-graph, mcp, context-engineering]
---

Every AI coding assistant faces the same bottleneck: it can only reason about
what fits in its context window. On a small project that is no problem —
paste the repo, ask the question. On a real C# monorepo with thousands of
types, it becomes *the* problem.

## The two default strategies, and why they fail

### Strategy one: dump the files

The brute-force approach hands the model whole files — the one you are
editing, plus whatever looks related. It fails in both directions at once:

- **Too much:** most of every file is irrelevant to the question. You pay
  for tokens that carry no signal.
- **Too little:** the behavior you ask about usually lives *between* files —
  an interface here, three implementations there, a decorator registered in
  a DI container nobody remembers.

### Strategy two: embeddings

Embeddings retrieve text that *resembles* the question. But resemblance is
not relevance. The method that breaks when you change an interface does not
share vocabulary with that interface. It shares a **compile-time
relationship** with it. No embedding captures that reliably, and the index
goes stale the moment the code changes.

## What the compiler already knows

Here is the thing: a complete, precise graph of your codebase already
exists. The C# compiler builds it on every compilation — every symbol, every
type, every call, every dependency. Then it throws that graph away the
moment it has emitted IL.

GraphSlice builds that graph and keeps it. A purpose-built tree walker reads
your solution's source directly. It resolves symbols, types, and calls
across projects, then writes the result as a **semantic code graph**: nodes
for solutions, projects, types, and methods; edges for the relationships
between them — calls edges (`CALLS`), inheritance, references, and package
dependencies.

## Context slices, not searches

A graph that cannot fit in a context window is no better than a repo that
cannot fit in a context window. The unit of delivery matters. GraphSlice
serves **context slices** — the minimal subgraph that answers one question:

```text
> what breaks if I change IPaymentProcessor?

IPaymentProcessor (interface, Billing.Core)
├── implemented by StripeProcessor       (Billing.Stripe)
├── implemented by InvoiceProcessor      (Billing.Invoicing)
├── injected into CheckoutService..ctor  (Web.Checkout)
└── mocked in PaymentProcessorTests      (Billing.Tests)
```

That is the whole answer. Four dependency paths, a few hundred tokens —
instead of forty files and a prayer.

## Why MCP is the right delivery channel

GraphSlice serves context slices over the
[Model Context Protocol](https://modelcontextprotocol.io) (MCP), so any
MCP-compatible agent can request them as tools:

- The agent asks a **structural question** ("who calls this?", "trace this
  dependency") instead of a text query.
- The graph does the reasoning about *structure*, so the agent can spend its
  reasoning budget on *intent*.
- Your repository is never uploaded or indexed by a third party. The graph
  runs where your code runs.

## The payoff

Correct context, not just nearby context. Smaller windows, flatter costs as
the repo grows, and answers grounded in how the software actually fits
together. Your AI assistant stops being a very confident text search. It
becomes an engineer with the graph in hand.
