Files
mcp-ue/CLAUDE.md
Pierre-Marie Charavel 77c972977a Fix search_source: pass env vars via mcp.json interpolation, search Plugins/, cap at 40 total lines
- .mcp.json: pass UE_ENGINE_ROOT and UE_DOCS_PATH via ${VAR} interpolation so the
  MCP server subprocess inherits them without hardcoding paths
- search_source: search both Engine/Source/ and Engine/Plugins/ (path_hint applied
  under both); switch from -m 40 (per-file cap) to streaming Popen with a true
  40-line total cap; fix UE_ENGINE_ROOT to point at Engine/ not the repo root
- Update README and CLAUDE.md to reflect the above

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 18:11:46 -05:00

3.9 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Purpose

UnrealDocGenerator is a tool for generating documentation from Unreal Engine C++ header files and exposing it to Claude via an MCP server for item-granularity lookups.

Current State

Implementation complete. Scripts live in docgen/:

  • docgen/ue_parser.py — Parses UE headers into dataclasses
  • docgen/ue_markdown.py — Renders parsed data as Markdown (ultra-compact format, documented items only)
  • docgen/generate.py — CLI entry point; two-pass pipeline (parse-all → build type index → render-all)
  • ue_mcp_server.py — MCP server exposing 5 tools for item-granularity doc lookups
  • .mcp.json — Registers the MCP server with Claude Code (stdio transport)

Usage

python docgen/generate.py <input> [input2 ...] <output_dir>

python docgen/generate.py Runtime/Engine/ Runtime/AIModule/ docs/   # multiple directories
python docgen/generate.py Runtime/Engine/Classes/GameFramework/Actor.h docs/  # single file

Output: one .md per .h + docs/type-index.txt (compact TypeName: path/to/File.md lookup).

The last argument is always the output directory. All preceding arguments are inputs (files or directories, processed recursively).

MCP Server

ue_mcp_server.py exposes 5 tools Claude can call directly:

Tool Purpose
search_types(pattern) Regex search over type-index.txt — locate a type before fetching details
get_class_overview(class_name) Compact view: description + inherits + property/function name lists
get_member(class_name, member_name) Full doc for one function or property (all overloads)
get_file(relative_path) Full .md file — use when you need delegates, enums, or multiple classes
search_source(pattern, path_hint) Grep UE .h files in Engine/Source/ and Engine/Plugins/; path_hint applied under both; returns up to 40 lines total

Requires pip install mcp. Reads $UE_DOCS_PATH; search_source also requires $UE_ENGINE_ROOT (must point to the Engine/ directory, e.g. /path/to/UnrealEngine/Engine).

.mcp.json passes both vars via ${VAR} interpolation — no paths hardcoded.

Typical query flow: search_typesget_class_overviewget_member (~3 calls, ~15 lines vs ~100 lines for a full file read).

Architecture Notes

  • Parser uses a position-based scanner, not line-by-line regex, to handle nested braces correctly.
  • find_matching_close() extracts balanced {}/() while skipping //, /* */, and string literals.
  • Only items with actual C++ doc comments (/** */) are included in output (_has_doc() filter).
  • Two-pass pipeline in generate.py: Pass 1 parses all files, Pass 2 renders with cross-reference links.
  • Multi-input: each (header, base) pair tracks its own base dir for correct relative output paths.
  • Inline cross-references: base class names linked to their .md when in corpus (_make_type_link()).
  • Deprecated functions excluded from output (not f.is_deprecated in visibility filter).
  • Enums with no value descriptions use compact inline format (Values: A, B, C) instead of a table.
  • Placeholder descriptions (------//) filtered by _PLACEHOLDER_RE in _fn_body().
  • Headers with no documented content: render_header() returns "", generate.py skips writing the file and filters those types from type-index.txt to avoid dead entries.

Critical Gotchas

  • Never use \s inside a [...] character class with *? on C++ source — causes catastrophic regex backtracking. Use line-based scanning instead.
  • Identifier regex must be r'\w+', not r'[\w:~]+' — the latter consumes public: as one token, breaking access specifier detection (all members become private).
  • Module name casing: use _caps_to_camel() (not .title()) — AIMODULE.title()Aimodule instead of AIModule.