Files
integration/Plugins/UEWingman/ue-wingman.py

78 lines
2.0 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
"""
Human-friendly MCP test client.
2026-03-31 16:43:28 -04:00
Usage: ue-wingman.py <command> [key=value ...]
2026-04-04 02:21:04 -04:00
Values starting with '[' or '{' are parsed as JSON.
"""
import sys
import json
import socket
HOST = "localhost"
2026-03-23 19:34:42 -04:00
PORT = 9851
TIMEOUT = 120
2026-03-19 00:40:27 -04:00
def main():
args = sys.argv[1:]
if not args:
2026-04-04 02:21:04 -04:00
print("Usage: ue-wingman.py <command> [key=value ...]")
sys.exit(1)
msg = {"command": args[0]}
for arg in args[1:]:
key, _, value = arg.partition("=")
if value and value[0] in ('[', '{'):
try:
2026-04-04 02:21:04 -04:00
value = json.loads(value)
2026-03-31 16:43:28 -04:00
except json.JSONDecodeError as e:
2026-04-04 02:21:04 -04:00
print(f"Bad JSON in {key}: {e.msg}")
sys.exit(1)
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) + "\0").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)
except json.JSONDecodeError:
print("Error: response is not valid JSON.")
sys.exit(1)
if not isinstance(parsed, list):
print("Error: response is not a list of content blocks.")
sys.exit(1)
for block in parsed:
if not (isinstance(block, dict)
and block.get("type") == "text"
and isinstance(block.get("text"), str)):
print("Error: response contains a non-text block.")
sys.exit(1)
print("\n---\n".join(block["text"] for block in parsed))
if __name__ == "__main__":
main()