Building an MCP server for Godot: lessons from week one

Whole-project analysis, debug interpretation, and the parts I got wrong.

I've been building an MCP server that gives Claude meaningful access to a Godot project — not just file reading, but actual semantic understanding of scenes, signals, and the runtime debug output. Week one is done. Here's what I learned.

The naive approach fails fast

My first version exposed three tools: read_scene, list_scripts, and get_debug_output. Claude could now see things, but it couldn't reason about them, because Godot scenes are graphs and I was handing them over as flat text.

A scene file looks like XML-flavored INI. Nodes reference each other by relative path. Signals connect across hierarchy. If you give Claude the raw file, it can read the words but not the relationships.

The fix: a scene-graph tool

I added a describe_scene tool that returns a structured representation:

{
  "root": "Player",
  "type": "CharacterBody2D",
  "children": [
    { "name": "Sprite", "type": "AnimatedSprite2D" },
    { "name": "Hitbox", "type": "Area2D" }
  ],
  "scripts": ["res://player.gd"],
  "signals_out": [
    { "from": "Hitbox", "signal": "body_entered", "to": "Player.on_hit" }
  ]
}

Now Claude can answer "where does Player's hit detection happen" without reading three files. It just asks the tool.

What I got wrong

I assumed debug output was a stream. It is — but Godot's print system interleaves stderr, stdout, and the engine's own messages, and timestamps aren't always present. My first parser silently dropped half the output because it didn't match my expected format.

The fix was embarrassingly mundane: capture everything, tag the source, hand the agent unfiltered output with a flag. Stop trying to be clever about what matters.

Coming next

Animation graph traversal, profiler output as structured data, and a tool for asking "what would change if I renamed this signal." The animation piece is genuinely hard — I'll write it up when it works.