Skip to main content
Glama

UnrealBlueprintMCP

by BestDev
test_mcp_server.py9.85 kB
#!/usr/bin/env python3 """ Test MCP Server for UnrealBlueprintMCP Plugin This script implements a simple WebSocket server that mimics the Python MCP server to test the Unreal Engine plugin's WebSocket client functionality. It supports the JSON-RPC 2.0 protocol and handles the blueprint operations that the Unreal plugin expects. """ import asyncio import websockets import json import logging from datetime import datetime from typing import Dict, Any, Optional # Configure logging logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) class MCPTestServer: """Test MCP Server implementation for Unreal Engine plugin testing""" def __init__(self, host: str = "localhost", port: int = 8080): self.host = host self.port = port self.connected_clients = set() async def register_client(self, websocket): """Register a new client connection""" self.connected_clients.add(websocket) logger.info(f"Client connected from {websocket.remote_address}") async def unregister_client(self, websocket): """Unregister a client connection""" self.connected_clients.discard(websocket) logger.info(f"Client disconnected from {websocket.remote_address}") async def handle_message(self, websocket, message: str) -> Optional[str]: """Handle incoming JSON-RPC 2.0 message from client""" try: data = json.loads(message) logger.info(f"Received message: {data}") # Validate JSON-RPC 2.0 format if not self.validate_jsonrpc(data): return self.create_error_response(None, -32600, "Invalid Request") # Extract request details request_id = data.get("id") method = data.get("method") params = data.get("params", {}) # Process the request if method == "create_blueprint": return await self.handle_create_blueprint(request_id, params) elif method == "set_property": return await self.handle_set_property(request_id, params) elif method == "add_component": return await self.handle_add_component(request_id, params) elif method == "compile_blueprint": return await self.handle_compile_blueprint(request_id, params) elif method == "get_server_status": return await self.handle_get_server_status(request_id, params) else: return self.create_error_response(request_id, -32601, f"Method not found: {method}") except json.JSONDecodeError: return self.create_error_response(None, -32700, "Parse error") except Exception as e: logger.error(f"Error handling message: {e}") return self.create_error_response(None, -32603, "Internal error") def validate_jsonrpc(self, data: Dict[str, Any]) -> bool: """Validate JSON-RPC 2.0 format""" return ( isinstance(data, dict) and data.get("jsonrpc") == "2.0" and "method" in data and isinstance(data["method"], str) ) def create_success_response(self, request_id: str, result: Dict[str, Any]) -> str: """Create a successful JSON-RPC 2.0 response""" response = { "jsonrpc": "2.0", "id": request_id, "result": result } return json.dumps(response) def create_error_response(self, request_id: Optional[str], code: int, message: str) -> str: """Create an error JSON-RPC 2.0 response""" response = { "jsonrpc": "2.0", "id": request_id, "error": { "code": code, "message": message } } return json.dumps(response) async def handle_create_blueprint(self, request_id: str, params: Dict[str, Any]) -> str: """Handle create_blueprint request""" blueprint_name = params.get("blueprint_name", "") parent_class = params.get("parent_class", "Actor") asset_path = params.get("asset_path", "/Game/Blueprints/") logger.info(f"Creating blueprint: {blueprint_name} (parent: {parent_class}) at {asset_path}") # Simulate blueprint creation await asyncio.sleep(0.1) # Simulate processing time result = { "success": True, "message": f"Blueprint '{blueprint_name}' created successfully", "blueprint_path": f"{asset_path}{blueprint_name}", "parent_class": parent_class, "timestamp": datetime.now().isoformat() } return self.create_success_response(request_id, result) async def handle_set_property(self, request_id: str, params: Dict[str, Any]) -> str: """Handle set_property request""" blueprint_path = params.get("blueprint_path", "") property_name = params.get("property_name", "") property_value = params.get("property_value", "") logger.info(f"Setting property {property_name} = {property_value} on {blueprint_path}") # Simulate property setting await asyncio.sleep(0.05) result = { "success": True, "message": f"Property '{property_name}' set to '{property_value}'", "blueprint_path": blueprint_path, "timestamp": datetime.now().isoformat() } return self.create_success_response(request_id, result) async def handle_add_component(self, request_id: str, params: Dict[str, Any]) -> str: """Handle add_component request""" blueprint_path = params.get("blueprint_path", "") component_type = params.get("component_type", "") component_name = params.get("component_name", "") logger.info(f"Adding component {component_name} ({component_type}) to {blueprint_path}") # Simulate component addition await asyncio.sleep(0.1) result = { "success": True, "message": f"Component '{component_name}' of type '{component_type}' added successfully", "blueprint_path": blueprint_path, "component_name": component_name, "component_type": component_type, "timestamp": datetime.now().isoformat() } return self.create_success_response(request_id, result) async def handle_compile_blueprint(self, request_id: str, params: Dict[str, Any]) -> str: """Handle compile_blueprint request""" blueprint_path = params.get("blueprint_path", "") logger.info(f"Compiling blueprint: {blueprint_path}") # Simulate compilation await asyncio.sleep(0.2) result = { "success": True, "message": f"Blueprint '{blueprint_path}' compiled successfully", "blueprint_path": blueprint_path, "compilation_time": "0.2s", "timestamp": datetime.now().isoformat() } return self.create_success_response(request_id, result) async def handle_get_server_status(self, request_id: str, params: Dict[str, Any]) -> str: """Handle get_server_status request""" logger.info("Getting server status") result = { "online": True, "version": "1.0.0-test", "server_name": "MCPTestServer", "uptime": "N/A", "connected_clients": len(self.connected_clients), "supported_operations": [ "create_blueprint", "set_property", "add_component", "compile_blueprint", "get_server_status" ], "supported_parent_classes": [ "Actor", "Pawn", "Character", "ActorComponent", "SceneComponent", "UserWidget", "Object" ], "timestamp": datetime.now().isoformat() } return self.create_success_response(request_id, result) async def handle_client(self, websocket, path): """Handle a client connection""" await self.register_client(websocket) try: async for message in websocket: response = await self.handle_message(websocket, message) if response: await websocket.send(response) logger.info(f"Sent response: {response}") except websockets.exceptions.ConnectionClosed: logger.info("Client connection closed") except Exception as e: logger.error(f"Error in client handler: {e}") finally: await self.unregister_client(websocket) async def start_server(self): """Start the WebSocket server""" logger.info(f"Starting MCP test server on {self.host}:{self.port}") async with websockets.serve(self.handle_client, self.host, self.port): logger.info(f"MCP test server running on ws://{self.host}:{self.port}") logger.info("Waiting for connections from Unreal Engine plugin...") await asyncio.Future() # Run forever async def main(): """Main entry point""" server = MCPTestServer() try: await server.start_server() except KeyboardInterrupt: logger.info("Server stopped by user") except Exception as e: logger.error(f"Server error: {e}") if __name__ == "__main__": asyncio.run(main())

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/BestDev/unreal_bp_mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server