Chapter 10 of 15 10 min intermediate

Debugging With MCP

One bug, start to finish

Verified against a working setup on 2026-08-10

Chapters that list capabilities do not show you how a session actually goes. This one walks a single realistic bug end to end, and the shape it follows — look, decide, change, verify — is the shape most good sessions follow.

The bug

A NullReferenceException fires on the first frame after entering play mode. The player does not move. The stack trace points into your own controller.

Step 1: look

You
text
Read my Unity console. Show me the full stack trace for the
NullReferenceException, then open the file it points at.
Do not change anything yet.

This is deliberately narrow. It asks for one thing, forbids edits, and tells the model where to look next. What comes back is your actual trace and your actual file — not a guess about what a null reference usually means.

Ending with "do not change anything yet" is the single highest-value habit in this whole guide. It separates diagnosis from action, and diagnosis is where you catch a wrong mental model before it becomes a wrong edit.

Step 2: narrow it

Say the trace lands on a line using groundCheck. There are only two possibilities: the field was never assigned in the Inspector, or something reassigned it. The model can check the first directly.

You
text
Inspect the Player GameObject in the open scene. List every
serialised field on PlayerController2D and tell me which ones
are unassigned.

This is the step that is genuinely tedious by hand and genuinely fast with MCP. It reads the live scene, not the file on disk, so it sees what Unity actually has loaded.

An unassigned SerializeField reads as null at runtime with no compile error — the class of bug that GameObjects & Components covers, and the single most common cause of a first-frame null reference in Unity.

Step 3: decide

This step is yours. The model has told you groundCheck is empty. You decide whether the right fix is assigning it in the Inspector, finding the child in Awake, or failing loudly instead of silently.

Skipping this step is how people end up with code they did not choose. The model will happily pick for you, and its pick is often reasonable and occasionally wrong for reasons only you know.

Step 4: change, narrowly

You
text
In PlayerController2D.cs only, add an Awake check that logs a
clear error naming the missing field and disables the component
if groundCheck is unassigned. Then verify the script compiles.
What it should produce
C#
private void Awake()
{
    rb = GetComponent<Rigidbody2D>();

    if (groundCheck == null)
    {
        Debug.LogError($"{name}: Ground Check is not assigned.", this);
        enabled = false;
        return;
    }
}
Passing this as the second argument to Debug.LogError makes the console entry clickable — it selects the offending object in the Hierarchy. Small, and it turns a vague error into a direct answer.

Step 5: verify

"Then verify the script compiles" closes the loop. The model re-reads the console after Unity recompiles and confirms its own edit was clean, instead of handing you code that does not build.

Unity stops answering MCP calls while it recompiles, so a tool call right after an edit often fails. That is expected. Retrying after a second or two usually just works — it is not a broken setup.

Why this beats pasting the error into a chat

  • It read your real stack trace, not your description of it.
  • It checked the live scene, which no pasted snippet contains.
  • It edited one named file, so the diff is trivial to review.
  • It confirmed the result compiled before claiming success.

What to take away

  • Look, decide, change, verify — in that order, every time.
  • Forbid edits during the diagnosis step.
  • Scope every change to a named file or the open scene.
  • End code prompts with "verify it compiles".
  • Expect tool calls to fail briefly while Unity recompiles.