
# Handler Refactor Instructions

Plugins/BlueprintMCP/Source/BlueprintMCP contains an MCP server that allows
Claude Code to control Unreal functions. MCP servers accept different
commands; each command has a "handler."

We are converting all handlers from an old style to a new style. In the old
style, each handler is a method of FMCPServer. In the new style, each
handler is a UCLASS derived from IMCPHandler. You will be assigned one
source file to convert. **Only modify that one file.**

## Step 1: Study the Existing Code

Before editing, read these files carefully:

- `MCPHandler.h` — the IMCPHandler interface and marker structs
- `MCPUtils.h` — utility functions available to handlers
- `MCPAssetFinder.h` — asset lookup helpers (FindAsset, LoadAsset, etc.)
- `MCPHandlers_Interfaces.h` — a clean example of new-style handlers
- `MCPHandlers_Validation.h` — another example (shows Optional params, bool, int32)
- `MCPHandlers_AnimMutation.h` — another example (shows FMCPJsonArray)

All of these are in `Plugins/BlueprintMCP/Source/BlueprintMCP/`.

## Step 2: Convert Your File

Each old-style handler function becomes a new-style UCLASS. The mechanical
steps are:

### 2a. Change the file header

Replace the old includes with this pattern:

```cpp
#pragma once

#include "CoreMinimal.h"
#include "MCPHandler.h"
#include "MCPAssetFinder.h"
#include "MCPUtils.h"
// ... any other includes the handlers actually need ...
#include "MCPHandlers_YourFile.generated.h"
```

Remove `#include "MCPServer.h"` — new-style handlers don't need it.

Remove any includes that are no longer used after conversion. Keep only
what the handler bodies actually reference.

### 2b. Wrap each handler in a UCLASS

Each old-style function like this:

```cpp
void FMCPServer::HandleFoo(const FJsonObject* Json, FJsonObject* Result)
{
    FString Name = Json->GetStringField(TEXT("name"));
    // ... body ...
}
```

Becomes:

```cpp
UCLASS(meta=(ToolName="the_mcp_tool_name"))
class UMCPHandler_Foo : public UObject, public IMCPHandler
{
    GENERATED_BODY()

public:
    UPROPERTY(meta=(Description="Human-readable description of this parameter"))
    FString Name;

    virtual FString GetDescription() const override
    {
        return TEXT("Human-readable description of what this tool does.");
    }

    virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
    {
        // ... body (minus the parameter extraction) ...
    }
};
```

### 2c. Convert parameters to UPROPERTY fields

- Each `Json->GetStringField(TEXT("foo"))` at the top of the handler becomes
  a `UPROPERTY` field on the class. The framework populates these
  automatically before calling `Handle()`.

- **Naming rule**: The UPROPERTY field name's first character gets
  lowercased to produce the JSON key. So `FString Blueprint;` maps to
  JSON key `"blueprint"`. `FString PackagePath;` maps to `"packagePath"`.
  Choose field names so that this automatic mapping produces the correct
  JSON key (i.e. the same key the old code was reading).

- **Required vs optional**: Fields are required by default. Add
  `meta=(Optional, Description="...")` for optional parameters. Optional
  fields should have default values (e.g. `bool Foo = false;`,
  `int32 Limit = 0;`, `FString Bar;` — empty string is the default).

- **Supported types**: `FString`, `bool`, `int32`, `float`, `FName`.
  For JSON arrays use `FMCPJsonArray` (has `.Array` field of type
  `TArray<TSharedPtr<FJsonValue>>`). For JSON objects use `FMCPJsonObject`
  (has `.Json` field of type `TSharedPtr<FJsonObject>`).

- **Remove manual extraction**: Delete the `Json->GetStringField()`,
  `Json->GetBoolField()`, etc. lines that read parameters. The UPROPERTY
  fields already contain the values. You can still use `Json->HasField()`
  to check whether an optional field was actually provided (for cases
  where you need to distinguish "not provided" from "provided as default
  value").

- **Remove manual validation of required fields**: The framework already
  returns an error if a required UPROPERTY field is missing from JSON.
  Delete checks like `if (Name.IsEmpty()) return MakeErrorJson(...)` for
  required FString fields. However, keep validation that checks field
  *content* (e.g. "must start with /Game").

### 2d. Avoid UPROPERTY / local variable name conflicts

If the old code has a local variable with the same name as your new
UPROPERTY field (e.g. UPROPERTY `FString Blueprint;` and local
`UBlueprint* Blueprint`), rename the local variable. Convention:
append `Obj` — e.g. `UBlueprint* BlueprintObj`, `USkeleton* SkeletonObj`.

### 2e. Tool name

The `ToolName` in the UCLASS meta must exactly match the tool name string
that was used in the old-style `H(TEXT("tool_name"), ...)` registration
in MCPServer.cpp. If you're unsure, search MCPServer.cpp for the old
handler function name to find the tool name.

### 2f. GetDescription()

Write a concise 1-2 sentence description of what the tool does. This is
shown to the LLM that calls the tool.

### 2g. Separator between classes

Put this separator between each UCLASS:

```cpp
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
```

## Step 3: Rename the File

After conversion, rename the file from `.cpp` to `.h`. The file is now a
header — UHT will process the GENERATED_BODY() macros during build.

## What NOT to Do

- **Do NOT modify MCPServer.h or MCPServer.cpp.** We will clean up old
  registrations separately.
- **Do NOT modify MCPHandlers.cpp** (the include aggregator). We will add
  the new include separately.
- **Do NOT add `#include "MCPServer.h"`** — new-style handlers are
  self-registering via UHT reflection and don't need it.
- **Do NOT change the handler logic.** Convert the structure, not the
  behavior. This is a mechanical refactor. If you see a bug that can be
  fixed within your file (e.g. a typo), fix it. But if you see a bug that
  would require editing other files to fix, leave the code as-is and insert
  a prominent comment block like this:
  ```cpp
  // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  // BUG: <description of the bug and what needs to change>
  // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  ```
  Another agent will deal with it later.
- **Do NOT rename JSON output fields.** The tool's output format must stay
  identical.
- **Do NOT add or remove handlers.** Convert exactly what's there.

## Files to Convert

Each of these `.cpp` files contains old-style handlers to convert:

1. `MCPHandlers_Read.cpp`
2. `MCPHandlers_Discovery.cpp`
3. `MCPHandlers_Graphs.cpp`
4. `MCPHandlers_Variables.cpp`
5. `MCPHandlers_Params.cpp`
6. `MCPHandlers_Dispatchers.cpp`
7. `MCPHandlers_Components.cpp`
8. `MCPHandlers_Snapshot.cpp`
9. `MCPHandlers_MaterialRead.cpp`
10. `MCPHandlers_MaterialMutation.cpp`
11. `MCPHandlers_MaterialInstance.cpp`
12. `MCPHandlers_StateMachine.cpp`
