---
title: "Why your AI assistant should query your architecture, not your files"
description: "File dumps and vector search 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's a non-issue — paste
the repo, ask the question. On a real C# monorepo with thousands of types, it
becomes *the* issue.

## The two default strategies, and why they fail

### Strategy one: dump the files

The brute-force approach is to hand the model whole files — the one you're
editing, plus whatever looks related. It fails in both directions at once:

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

### Strategy two: vector search

Embeddings retrieve text that *looks like* the question. But code similarity
is not code relevance. The method that breaks when you change an interface
doesn't share vocabulary with the interface — it shares a **compile-time
relationship** with it. No embedding captures that reliably, and the index
drifts out of date the moment the code changes.

## What the compiler already knows

Here's the thing: a complete, precise map of your codebase already exists.
The C# compiler builds it on every compilation — every symbol, every type,
every call edge, every dependency. It just throws the map away when it's done
emitting IL.

GraphSlice builds that map itself. A purpose-built tree walker reads your
solution's source directly — resolving symbols, types, and call edges across
projects — and materializes the result as a **semantic code graph**: nodes for
solutions, projects, types, and methods; edges for calls, inheritance,
references, and package dependencies.

## Slices, not searches

A graph you can't fit in a context window is no better than a repo you can't
fit in a context window. The unit of delivery matters. GraphSlice serves
**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's the whole answer. Four dependency paths, a few hundred tokens — instead
of forty files and a prayer.

## Why MCP is the right delivery channel

Slices are served over the [Model Context Protocol](https://modelcontextprotocol.io),
which means any MCP-compatible assistant can request them as tools:

- The model asks a **structural question** ("who calls this?", "trace this
  dependency") instead of a text query.
- The graph does the reasoning about *structure*, so the model 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 and
starts being an engineer with the blueprints in hand.
