Claude Code Codebase Context: CLAUDE.md, MCP, and Workflow

Give Claude Code structural context up front with a curated CLAUDE.md, MCP tools for definitions and callers, and a five-step session workflow.

By The OpenVisio Team · · 14 min read

Claude Code is good at finding its way around a repository with nothing but a shell. It lists directories, greps for names, opens files, and builds a picture as it goes. On a small project that is enough. On a large one, the exploration phase starts to dominate: the agent spends a large share of each session rediscovering where things live, reads whole files to answer questions that needed one function, and occasionally builds its plan on the wrong module because the first grep hit looked plausible.

This guide covers how to give Claude Code structural context up front, so it starts each task closer to the answer. There are three layers: a CLAUDE.md file that carries the facts a newcomer would need, an MCP server that answers structural questions (who calls this, what depends on that) without bulk file reads, and a session workflow that uses both deliberately. None of it requires changing how you write code.

Key takeaways

  • CLAUDE.md is for durable, human-curated facts: how to build and test, where the important boundaries are, and the rules that are not obvious from the code. Keep it short and specific.
  • An MCP server gives Claude Code structured tools, such as symbol lookup and call tracing, so it can ask narrow questions instead of reading files speculatively.
  • Register servers with claude mcp add, and use project scope when the whole team should share the same configuration.
  • Start each non-trivial task with a context step (resolve the task to files and symbols), then a plan, then edits, then verification.
  • Measure the setup by outcomes: fewer wrong-file edits, fewer exploratory reads, and plans that survive review.

Why exploration gets expensive on large repos

A coding agent has a fixed context window and no memory between sessions. Every task begins with the same question: where is the code that matters here? With only shell tools, the agent answers it by sampling. It runs grep -rn "invoice", gets 400 hits, opens the five that look most promising, and infers the rest. That approach has three predictable costs.

First, it is token-heavy. Opening a 1,200-line file to read one 30-line function spends most of the budget on text that never influences the change.

Second, it is lossy. Text search finds names, not relationships. It will not tell the agent that applyDiscount is called from three places, one of which is a background job that grep missed because the call goes through a dispatcher.

Third, it is repeated. Next session, the agent rediscovers the same layout from scratch.

The fix is not a bigger context window. It is better inputs: a short file of curated facts, plus tools that return structure on demand.

Layer 1: a CLAUDE.md that earns its tokens

Claude Code reads a CLAUDE.md file at the root of the project and includes it in context at the start of a session. You can also place additional CLAUDE.md files in subdirectories for area-specific notes, and keep a personal one in your home configuration for preferences that apply to every project. The /init command will draft a starting file by scanning the repo, which is a reasonable first pass that you should then edit hard.

Because the file is loaded every session, every line has a recurring cost. Put in only what the agent cannot cheaply discover and would otherwise get wrong.

What belongs in it

# Project notes for agents

## Build and test
- Install: `pnpm install`
- Typecheck: `pnpm typecheck`
- Unit tests for one package: `pnpm --filter @acme/billing test`
- Never run `pnpm test` at the root; it starts the e2e suite and takes 20 minutes.

## Layout
- `apps/web`: Next.js frontend. Server code lives in `app/**/route.ts` and `lib/server/`.
- `packages/billing`: all pricing and invoice logic. The web app must not import from `packages/billing/internal`.
- `services/worker`: queue consumers. Jobs are registered in `services/worker/src/registry.ts`.

## Rules
- Money is always integer cents (`amountCents`). Never use floats for currency.
- Database migrations are generated with `pnpm db:generate`; do not hand-edit files in `migrations/`.
- Feature flags are read through `lib/flags.ts`, never from `process.env` directly.

## Before you finish
- Run typecheck and the tests for every package you touched.
- Summarize which files changed and why.

Notice what is missing: no description of every folder, no restated framework documentation, no style rules a linter already enforces. If the formatter handles it, leave it out. For a longer treatment of what to include and what to cut, see writing AGENTS.md and CLAUDE.md files.

Keep it honest

A CLAUDE.md that describes last year's layout is worse than none, because the agent will trust it. Treat it like code: change it in the same pull request that changes the thing it describes, and have reviewers check it. A quick test is to ask a new teammate to read it and point out anything that surprised them in the actual code.

Layer 2: structural context over MCP

CLAUDE.md carries facts that change slowly. Structure changes with every commit: which functions call which, what imports a module, which files are central. That is where an MCP server helps. The Model Context Protocol lets Claude Code call external tools that return structured results, and a code graph server can answer questions like "who calls applyDiscount" with exact file and line anchors instead of a pile of grep hits. The background is covered in using an MCP server for codebase context; here we focus on wiring it into Claude Code.

Registering a server

Claude Code manages MCP servers with the claude mcp subcommands. The general shape for a server that runs as a local process is:

# Add a stdio server for this project only (stored in your local config)
claude mcp add code-graph -- <command that starts the server> <args>

# Share it with the team: project scope writes a .mcp.json at the repo root
claude mcp add --scope project code-graph -- <command that starts the server> <args>

# Check what is registered
claude mcp list

Inside a session, the /mcp command shows connected servers and their status. Project scope is usually the right choice for a code graph server, because you want every engineer and every agent session to get the same tools. Commit the resulting .mcp.json like any other config, and keep secrets out of it; use environment variables for tokens.

Which tools matter

The useful tool set for code understanding is small. Whatever server you use, look for equivalents of these:

Question the agent hasTool shapeWhy it beats grep
Which files matter for this task?resolve a task description to ranked files and symbolsStarts from relevance, not string matches
Where is this symbol defined?find a symbol by name or descriptionReturns definitions, not every mention
Who calls this function?trace inbound and outbound callsFollows relationships text search misses
What breaks if I change this file?list dependents of a file or moduleGives the blast radius before editing
What is around this file?return the local import neighborhoodBounded context instead of a whole tree
Where is the risk?rank hotspots by churn and centralityPoints review effort at fragile code

Tell the agent to use them

Registering tools is not enough. Agents fall back to habits, and the habit is shell search. Add a short instruction to CLAUDE.md:

## Code navigation
- For "where is X" or "who uses X" questions, use the code-graph MCP tools before grep.
- Start every non-trivial task by resolving the task description to files and symbols.
- Read only the line ranges the tools point to, not whole files.
- Use grep for config, docs, and string literals the graph does not model.

That last line matters. A code graph models code, and you still want plain search for YAML keys, error message text, and Markdown.

Layer 3: a session workflow that uses both

With facts in CLAUDE.md and structure behind MCP, the remaining lever is how you run a session. A workflow that holds up on large repos has five steps.

1. State the task with its boundary

Add a `taxExempt` boolean to customers. It should be settable in the admin
customer form and respected when invoices are calculated. Do not change the
public API. Scope: packages/billing, apps/web/app/admin/customers.

The scope line is the single most useful thing you can add. It tells the agent where to look first and where it should not wander.

2. Ask for context before a plan

Before planning, find the invoice calculation entry point, list its callers,
and list the files that import the customer model. Report file:line anchors.

With MCP tools available, this step is a handful of narrow calls that return a few dozen lines of structure. Without them, it is a long grep-and-read loop. Either way, you see what the agent believes about the code before it acts on that belief.

3. Review the plan, not just the diff

Ask for a numbered plan that names files. This is the cheapest point to catch a misunderstanding. If the plan edits packages/billing/internal from the web app, your CLAUDE.md rule was not seen or not followed; fix the instruction, not just the plan.

4. Edit in small steps with checks

Have the agent run the typecheck and the relevant package tests after each logical step, not only at the end. Long unverified edit sequences are where agents compound early mistakes.

5. Verify against dependents

Before finishing, ask the agent to re-check the dependents it listed in step 2. Did every caller of the changed function get updated or confirmed unaffected? This turns the initial context into a checklist for the end.

Plan mode, subagents, and long sessions

Claude Code offers a plan-oriented mode in which it investigates and proposes without editing. It pairs naturally with step 2 and 3 above: let it gather context and write the plan, review, then switch to editing.

For very large investigations, it can delegate exploration to subagents so that the main session receives a summary instead of every file it read. That keeps the main context focused on the change. The structural tools help here too: a subagent that can trace calls returns a tight answer rather than a long list of files it skimmed.

A worked example

Suppose the task is: "Invoices for annual plans are off by one day at month boundaries."

Without structural context, a typical session greps for annual, opens the plan model, opens a date utility, opens a test file, and edits the date utility. The fix passes the one test it touched. Review later finds that the same utility is used by the trial-expiry job, which now behaves differently.

With the setup above, the session looks different:

  1. The agent resolves the task and gets packages/billing/src/periods.ts:41 computePeriodEnd as the top symbol, with invoice.ts and trial-expiry.ts as callers.
  2. It traces callers of computePeriodEnd and reports three: invoice generation, proration, and the trial-expiry job.
  3. The plan proposes fixing the boundary math and adding tests for all three callers, and flags that the trial-expiry behavior will change.
  4. You decide whether that change is wanted before any code is written.

The difference is not that the agent got smarter. It had the dependents in front of it before it chose where to edit, which is the same thing a careful engineer does with an IDE's "find references". Our post on impact analysis before refactoring expands on this habit.

Common problems and fixes

  • The agent ignores the MCP tools. Check /mcp to confirm the server is connected, then make the CLAUDE.md instruction explicit about when to use them. Name the tools if needed.
  • Results look stale. A code graph reflects the revision it indexed. Re-index after branch switches and large merges, and prefer servers that report which revision an answer came from.
  • CLAUDE.md keeps growing. Move area-specific notes into subdirectory CLAUDE.md files and delete anything the agent has never needed. A shorter file that is always right beats a long one that is mostly right.
  • The agent reads whole files anyway. Ask for line-range reads explicitly, and make sure the tools return path:line anchors the agent can act on.

Setting this up with OpenVisio

OpenVisio indexes a repository locally and exposes its code graph over MCP with tools such as resolve_context, find_symbol, trace_calls, get_dependents, get_neighborhood, get_hotspots, and get_repo_skeleton. Registered with claude mcp add, those become the structural layer described above. The same graph powers the human side: Explore shows the architecture view and file tree an engineer would use to sanity-check what the agent reported.

Whatever tooling you choose, the pattern stays the same. Curate the few facts that do not change often, serve structure on demand, and run sessions that look before they leap. Claude Code then spends its budget on the change you asked for instead of on finding the code again.

Claude CodeCLAUDE.mdMCPcodebase contextAI agents

See it on your own repo

Paste a GitHub URL and get the day-one walkthrough — free, in your browser.

Index a repo

Keep reading