diff --git a/.mcp.json b/.mcp.json index 9e7c12b9..ae94da6b 100644 --- a/.mcp.json +++ b/.mcp.json @@ -2,7 +2,7 @@ "mcpServers": { "ue-wingman": { "command": "python3", - "args": ["tools/mcp-bridge.py"] + "args": ["Plugins/UEWingman/ue-wingman-mcp.py"] } } } diff --git a/Plugins/UEWingman/LICENSE.txt b/Plugins/UEWingman/LICENSE.txt index c52ca1d5..543a571f 100644 --- a/Plugins/UEWingman/LICENSE.txt +++ b/Plugins/UEWingman/LICENSE.txt @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2026 BlueprintMCP Contributors +Copyright (c) 2026 UE Wingman and BlueprintMCP Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Plugins/UEWingman/README.md b/Plugins/UEWingman/README.md index 2f1d7fa7..8323d18b 100644 --- a/Plugins/UEWingman/README.md +++ b/Plugins/UEWingman/README.md @@ -1,72 +1,177 @@ -= History +# UE Wingman -This plugin was originally vibe-coded by Claude Code. It -was then posted to David Gundry's github account, here: +UE Wingman is a tool that allows an AI to control the unreal +editor. When you're using it, it feels like the AI is right +there looking at the editor with you. You'll be able to +watch as it creates graph nodes and wires them together, +you'll see it add components to your blueprints, you'll see +it design widget hierarchies for you, and you'll see it write +shaders for your materials. - https://github.com/mirno-ehf/ue5-mcp +The tool is not complete, not by a long shot. There are +tons of Unreal Editor functions that the AI just can't +access yet. Even so, I think it's useful: it has pretty +comprehensive support to allow the AI agent to help create +blueprints, widget blueprints, and materials. -He released it under the MIT license. +## How Does it Work? -How do I know it was vibe coded? Because he says so: +This tool adds a command interpreter plugin to the Unreal +Editor. You can type commands, and the plugin in the editor +will execute them. You can actually type commands directly +from the command-line. Here's an example of what you might +see: -> For Humans: -> -> You're welcome here, but probably not in the way you'd -> expect. This project is built and maintained entirely by -> AI coding agents — Claude Code, Cursor, Copilot Workspace, -> and the like. We don't accept human-written code or -> human-opened issues. +``` + $ ue-wingman.py Graph_Dump Graph=/Game/Testing/BP_Test,graph:EventGraph + + node K2Node_Event_0: Event BeginPlay + output-pins OutputDelegate + + node K2Node_Event_2: Event Tick + output-pins OutputDelegate, DeltaSeconds +``` -Huh, interesting. I (Josh Yelon) downloaded the code, and -evaluated it. I was curious what vibe coding could do. -Here's what I found: +There are tons of commands built in: Graph_Dump, +GraphNode_Create, GraphPin_Connect, +BlueprintComponent_Create, Widget_Create, and so forth. +Using these commands, it's possible to examine and modify +blueprints, widgets, and materials. -* The code, overall, had issues, but in the end, it wasn't -that bad. It did work, mostly - and that matters. I wanted -my own working MCP server, and starting from a place where -you have working code is a lot easier than starting from -a blank slate. +But, of course, these commands aren't really intended for humans. +They're intended for an AI agent. The AI is given access to these +commands using what's called "Model Context Protocol," which is +a goofy name for "a mechanism that an AI can use to send +commands to other software." -* Claude really doesn't build any mechanisms to enforce -consistency. For example: there were all the handlers, and -then in a different file, declarations of all the handlers, -then in another file registrations of all the handlers with -the webserver, then in another place a list of all the -handlers that require undo support, then in an entirely -other directory, a list of all the handlers and their -parameters. If any of these lists got out of sync, it would -break. +## Why Choose this Particular Unreal Engine MCP? -* Claude doesn't seem to care at all about extra layers upon -layers, or about dependencies. Rather than building an MCP -server in an unreal plugin, it built a *web* server in an -unreal plugin, then built an MCP-to-web translation program -in *javascript*. Requests to the server were getting -translated from json into URL parameters and then back into -json. Ouch. The javascript required installation of about -a thousand javascript libraries, some of which were not easy -to install. Why not just build an MCP server in the Unreal -plugin directly, skipping all the dependencies and -translation layers? +There are a *lot* of Unreal Engine MCPs out there. Some of +them are, shall we say, not carefully engineered. I'm a +reasonably skilled software engineer and I've designed +this plugin to be robust and capable of sustained development. -* Claude will repeat code over and over. I found endless -places where there were 10 copies of the same function, with -trivial variations, that could have all been merged into one -function with a parameter or two. When it does repeat code, -the repetitions are not generally consistent with each other: -one variant might have a bug, whereas another is fine. +This MCP is also designed to be as broadly general as +possible. I've seen many Unreal Engine MCPs that claim "can +create 22 different kinds of graph nodes!" This makes me +ask: why not just provide the *entire catalog* of all +possible graph nodes? I've seen MCPs claim "you can edit 15 +different material expression properties!" Why not provide +access to *all* editable material expression properties? +I've tried to make every tool in this MCP as capable as +possible, with as few limits as possible. -* There were lots of little edge-case bugs throughout the -code. Claude is actually not bad about noticing edge cases, -but it misses some. +This MCP is very extensible. Adding a new command requires +a relatively small amount of code. I'm hoping some others +in the community will eventually start contributing new +commands. -Despite all this, it was much easier to start from something -than to start from nothing. +## Installation -So, I undertook a massive refactoring effort. I did use -Claude Code extensively - in fact, I'd say Claude did 70% of -the work. But I monitored every step, and constantly pushed -Claude hard to use better software engineering practices. +There are three parts to UE Wingman: + +* The Unreal Plugin, which does 99% of the work. + +* The python program "ue-wingman.py" which a human can + use to send commands to the plugin. + +* The python program "ue-wingman-mcp.py", which an AI + can use to send commands to the plugin. + +If you build Unreal from source, the best way to install the +plugin is to drop the entire UEWingman source folder into +your Plugins folder. Then do a build. Restart the editor, and +go into your plugins configuration. Enable the UE Wingman +plugin. You're done. + +If you don't build from source, then unfortunately, you're +out of luck. Precompiled plugins must be built for every +different OS, for every different engine version. I just +don't have the means to do that right now. + +After installing the plugin, you need to install the two +python programs. They are both short and simple: all they +do is establish a network connection to the plugin, and then +send the command you typed. They require python 3.6 or later, +and no other dependencies. + +To install the human version, ue-wingman.py, just drop it into +a folder on your PATH. + +To install the AI version, ue-wingman-mcp.py, you have to +usually set up some config file for your AI agent. I use +Claude Code, for that, you have to create a file ".mcp.json" +in your project folder, and it needs to have this inside it: + +``` +{ + "mcpServers": { + "ue-wingman": { + "command": "python3", + "args": ["Plugins/UEWingman/ue-wingman-mcp.py"] + } + } +} +``` + +You can usually ask your AI agent for help creating this +config file. + +## The "User Manual" + +You might be interested in seeing the "user manual" for the +plugin. To get that, you type this: + +``` +$ ue-wingman.py UserManual +``` + +Of course, you're not the intended user: your AI agent is. +When the AI agent starts up ue-wingman-mcp, it is +automatically told to read the user manual. From there, the +User Manual says, among other things, that the AI agent can +get a listing of built-in commands. You can see that too: + +``` +$ ue-wingman.py ShowCommands +``` + +With these two commands at your disposal, you'll have a better +understanding of what exactly your AI agent is doing with this +plugin, and how it all works. + +## Fun things to Try + +I really started enjoying this plugin when I asked my agent +to make me a "cool looking material, something psychedelic +and weird." It made a neat kaleidoscope thing. I then +asked it to make me an animated rendering of the mandelbrot +set. It's fun to watch it do things like that. + +## History and Credits + +When I myself needed an MCP for unreal development, I did a +survey of the plugins out there. I ended up choosing a +plugin called "Blueprint MCP" by David Gundry: + + + +It was not bad, but it had some limitations, and I started +doing work to improve it. Incrementally, I ended rewriting +pretty much the whole thing. So this whole project is actually +a fork of Blueprint MCP. There's very little of the original +code remaining. However, you will find snippets here and there. + +Even though I ended up rewriting most of the code, it really +was useful to have a functioning starting point. It meant I +could improve one thing at a time, without having to try to +get everything working all at once. So I'm quite grateful +to David Gundry and his work. + +## Software License + +UE Wingman is licensed under the MIT license, a copy of which +is enclosed. Its predecessor (of which it is a fork) was also +under the MIT license, so everything works out. -The result, I think, is a pretty clean MCP server. diff --git a/Plugins/UEWingman/Source/UEWingman/Public/WingServer.h b/Plugins/UEWingman/Source/UEWingman/Public/WingServer.h index 2367f4c3..2bfb254f 100644 --- a/Plugins/UEWingman/Source/UEWingman/Public/WingServer.h +++ b/Plugins/UEWingman/Source/UEWingman/Public/WingServer.h @@ -83,7 +83,7 @@ private: // ----- TCP server ----- FSocket* ListenSocket = nullptr; - int32 Port = 9847; + int32 Port = 9851; bool bRunning = false; // ----- Client connections ----- diff --git a/tools/mcp-bridge.py b/Plugins/UEWingman/ue-wingman-mcp.py similarity index 92% rename from tools/mcp-bridge.py rename to Plugins/UEWingman/ue-wingman-mcp.py index 0150fcc5..fd8bbb23 100644 --- a/tools/mcp-bridge.py +++ b/Plugins/UEWingman/ue-wingman-mcp.py @@ -1,10 +1,9 @@ #!/usr/bin/env python3 """ -MCP stdio-to-TCP bridge for BlueprintMCP. +MCP stdio-to-TCP bridge for UE Wingman. Exposes a single MCP tool "unreal" that forwards JSON commands to the -BlueprintMCP TCP server in the Unreal Editor. The tool list is static, -so it works regardless of whether the editor is running at startup. +UE Wingman TCP server in the Unreal Editor. """ import sys @@ -12,12 +11,12 @@ import json import socket HOST = "localhost" -PORT = 9847 +PORT = 9851 CONNECT_TIMEOUT = 2 READ_TIMEOUT = 120 TOOL_DESCRIPTION = ( - "Send a command to the Unreal Editor's BlueprintMCP plugin. " + "Send a command to the Unreal Editor's UE Wingman plugin. " "The 'command' field specifies which operation to perform; " "additional fields are command-specific parameters. " 'Use {"command": "UserManual"} to get an overview. ' @@ -118,7 +117,7 @@ def handle_message(msg): return make_jsonrpc(msg_id, { "protocolVersion": "2024-11-05", "capabilities": {"tools": {}}, - "serverInfo": {"name": "blueprint-mcp", "version": "1.0.0"}, + "serverInfo": {"name": "ue-wingman", "version": "1.0.0"}, }) if method == "tools/list": diff --git a/tools/mcp-test.py b/Plugins/UEWingman/ue-wingman.py similarity index 70% rename from tools/mcp-test.py rename to Plugins/UEWingman/ue-wingman.py index b26e76d8..c2248e07 100755 --- a/tools/mcp-test.py +++ b/Plugins/UEWingman/ue-wingman.py @@ -2,9 +2,7 @@ """ Human-friendly MCP test client. -Usage: mcp-test.py ShowCommands - mcp-test.py ListBlueprintAssets filter=lx - mcp-test.py ShowCommands verbose=true +Usage: ue-wingman.py UserManual """ import sys @@ -12,22 +10,14 @@ import json import socket HOST = "localhost" -PORT = 9847 +PORT = 9851 TIMEOUT = 120 -# Map ASCII characters to the Unicode geometric delimiters used by the plugin. -DELIMITER_MAP = str.maketrans({ - '<': '◂', - '>': '▸', - '*': '◆', - '.': '◦', - '|': '│', -}) def main(): args = sys.argv[1:] if not args: - print("Usage: mcp-test.py ShowCommands [key=value ...]") + print("Usage: ue-wingman.py ShowCommands [key=value ...]") sys.exit(1) msg = {"command": args[0]} @@ -44,11 +34,6 @@ def main(): pass msg[key] = value - # Translate ASCII delimiter shortcuts to Unicode geometric shapes. - for key, value in msg.items(): - if isinstance(value, str): - msg[key] = value.translate(DELIMITER_MAP) - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(TIMEOUT) try: