diff --git a/Integration.code-workspace.tpl.json b/Integration.code-workspace.tpl.json index 1026349b..9a63bd9c 100644 --- a/Integration.code-workspace.tpl.json +++ b/Integration.code-workspace.tpl.json @@ -134,6 +134,25 @@ } }, "append2" : [ + { + "name": "BlueprintMCP Commandlet", + "request": "launch", + "program": "[UNREALENGINE]/Engine/Binaries/Linux/UnrealEditor-Linux-[DEBUG]-Cmd", + "preLaunchTask": "python3 build.py c++", + "args": [ + "[INTEGRATION]/Integration.uproject", + "-userdir=User/[USER]", + "-run=BlueprintMCP", + "-unattended" + ], + "cwd": "[INTEGRATION]", + "type": "lldb", + "console": "integratedTerminal", + "initCommands": [ + "command script import [UNREALENGINE]/Engine/Extras/LLDBDataFormatters/UEDataFormatters_2ByteChars.py", + "settings set target.inline-breakpoint-strategy always" + ] + }, { "name": "Luprex Server", "request": "launch", diff --git a/tools/mcp-test.py b/tools/mcp-test.py new file mode 100755 index 00000000..e79db40b --- /dev/null +++ b/tools/mcp-test.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +""" +Human-friendly MCP test client. + +Usage: mcp-test.py ShowCommands + mcp-test.py ListBlueprintAssets filter=lx + mcp-test.py ShowCommands verbose=true +""" + +import sys +import json +import socket + +HOST = "localhost" +PORT = 9847 +TIMEOUT = 120 + +def main(): + args = sys.argv[1:] + if not args: + print("Usage: mcp-test.py ShowCommands [key=value ...]") + sys.exit(1) + + msg = {"command": args[0]} + for arg in args[1:]: + key, _, value = arg.partition("=") + if value.lower() == "true": + value = True + elif value.lower() == "false": + value = False + else: + try: + value = int(value) + except ValueError: + pass + msg[key] = value + + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.settimeout(TIMEOUT) + try: + sock.connect((HOST, PORT)) + except (ConnectionRefusedError, socket.timeout, OSError) as e: + print(f"Cannot connect to {HOST}:{PORT} — is the editor running?") + sys.exit(1) + + sock.sendall((json.dumps(msg) + "\n").encode()) + + result = b"" + while True: + chunk = sock.recv(65536) + if not chunk: + break + result += chunk + if b"\0" in result: + break + + sock.close() + result = result[:result.index(b"\0")].decode() if b"\0" in result else result.decode() + + try: + parsed = json.loads(result) + print(json.dumps(parsed, indent=2)) + except json.JSONDecodeError: + print(result) + +if __name__ == "__main__": + main()