flockbay 0.10.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/README.md +56 -0
  2. package/bin/flockbay-mcp.mjs +56 -0
  3. package/bin/flockbay.mjs +78 -0
  4. package/dist/codex/flockbayMcpStdioBridge.cjs +383 -0
  5. package/dist/codex/flockbayMcpStdioBridge.d.cts +2 -0
  6. package/dist/codex/flockbayMcpStdioBridge.d.mts +2 -0
  7. package/dist/codex/flockbayMcpStdioBridge.mjs +381 -0
  8. package/dist/flockbayScreenshotGate-DJX3Is5d.mjs +136 -0
  9. package/dist/flockbayScreenshotGate-DkxU24cR.cjs +138 -0
  10. package/dist/index--o4BPz5o.cjs +10311 -0
  11. package/dist/index-CUp3juDS.mjs +10268 -0
  12. package/dist/index.cjs +43 -0
  13. package/dist/index.d.cts +1 -0
  14. package/dist/index.d.mts +1 -0
  15. package/dist/index.mjs +40 -0
  16. package/dist/lib.cjs +33 -0
  17. package/dist/lib.d.cts +957 -0
  18. package/dist/lib.d.mts +957 -0
  19. package/dist/lib.mjs +23 -0
  20. package/dist/runCodex-D3eT-TvB.cjs +3449 -0
  21. package/dist/runCodex-o6PCbHQ7.mjs +3446 -0
  22. package/dist/runGemini-Bt0oEj_g.mjs +3183 -0
  23. package/dist/runGemini-CBxZp6I7.cjs +3185 -0
  24. package/dist/types-C-jnUdn_.cjs +4498 -0
  25. package/dist/types-DGd6ea2Z.mjs +4450 -0
  26. package/kits/kit.open_world/kit.json +59 -0
  27. package/package.json +130 -0
  28. package/scripts/claude_local_launcher.cjs +73 -0
  29. package/scripts/claude_remote_launcher.cjs +16 -0
  30. package/scripts/claude_version_utils.cjs +391 -0
  31. package/scripts/ripgrep_launcher.cjs +33 -0
  32. package/scripts/session_hook_forwarder.cjs +49 -0
  33. package/scripts/test-codex-abort-history.mjs +77 -0
  34. package/scripts/unpack-tools.cjs +222 -0
  35. package/tools/licenses/difftastic-LICENSE +21 -0
  36. package/tools/licenses/ripgrep-LICENSE +3 -0
  37. package/tools/unreal-mcp/UPSTREAM_VERSION.md +8 -0
  38. package/tools/unreal-mcp/upstream/Docs/README.md +8 -0
  39. package/tools/unreal-mcp/upstream/Docs/Tools/README.md +7 -0
  40. package/tools/unreal-mcp/upstream/Docs/Tools/actor_tools.md +184 -0
  41. package/tools/unreal-mcp/upstream/Docs/Tools/blueprint_tools.md +268 -0
  42. package/tools/unreal-mcp/upstream/Docs/Tools/editor_tools.md +104 -0
  43. package/tools/unreal-mcp/upstream/Docs/Tools/node_tools.md +274 -0
  44. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Config/FilterPlugin.ini +8 -0
  45. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPBlueprintCommands.cpp +1160 -0
  46. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPBlueprintNodeCommands.cpp +924 -0
  47. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPCommonUtils.cpp +709 -0
  48. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPEditorCommands.cpp +896 -0
  49. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPProjectCommands.cpp +72 -0
  50. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPUMGCommands.cpp +544 -0
  51. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/MCPServerRunnable.cpp +321 -0
  52. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/UnrealMCPBridge.cpp +419 -0
  53. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/UnrealMCPModule.cpp +21 -0
  54. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPBlueprintCommands.h +34 -0
  55. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPBlueprintNodeCommands.h +27 -0
  56. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPCommonUtils.h +59 -0
  57. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPEditorCommands.h +40 -0
  58. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPProjectCommands.h +20 -0
  59. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPUMGCommands.h +82 -0
  60. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/MCPServerRunnable.h +34 -0
  61. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/UnrealMCPBridge.h +64 -0
  62. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/UnrealMCPModule.h +22 -0
  63. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/UnrealMCP.Build.cs +78 -0
  64. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/UnrealMCP.uplugin +36 -0
  65. package/tools/unreal-mcp/upstream/Python/README.md +40 -0
  66. package/tools/unreal-mcp/upstream/Python/pyproject.toml +22 -0
  67. package/tools/unreal-mcp/upstream/Python/scripts/actors/test_cube.py +203 -0
  68. package/tools/unreal-mcp/upstream/Python/scripts/blueprints/test_create_and_spawn_blueprints_with_different_components.py +497 -0
  69. package/tools/unreal-mcp/upstream/Python/scripts/blueprints/test_create_and_spawn_cube_blueprint.py +194 -0
  70. package/tools/unreal-mcp/upstream/Python/scripts/node/test_component_reference.py +267 -0
  71. package/tools/unreal-mcp/upstream/Python/scripts/node/test_create_bird_blueprint_with_input_and_camera.py +618 -0
  72. package/tools/unreal-mcp/upstream/Python/scripts/node/test_input_mapping.py +366 -0
  73. package/tools/unreal-mcp/upstream/Python/scripts/node/test_physics_variables.py +390 -0
  74. package/tools/unreal-mcp/upstream/Python/tools/blueprint_tools.py +420 -0
  75. package/tools/unreal-mcp/upstream/Python/tools/editor_tools.py +369 -0
  76. package/tools/unreal-mcp/upstream/Python/tools/node_tools.py +430 -0
  77. package/tools/unreal-mcp/upstream/Python/tools/project_tools.py +64 -0
  78. package/tools/unreal-mcp/upstream/Python/tools/umg_tools.py +333 -0
  79. package/tools/unreal-mcp/upstream/Python/unreal_mcp_server.py +398 -0
  80. package/tools/unreal-mcp/upstream/Python/uv.lock +521 -0
@@ -0,0 +1,398 @@
1
+ """
2
+ Unreal Engine MCP Server
3
+
4
+ A simple MCP server for interacting with Unreal Engine.
5
+ """
6
+
7
+ import logging
8
+ import socket
9
+ import sys
10
+ import json
11
+ import os
12
+ from contextlib import asynccontextmanager
13
+ from typing import AsyncIterator, Dict, Any, Optional
14
+ from mcp.server.fastmcp import FastMCP
15
+
16
+ # Configure logging with more detailed format
17
+ def _default_log_path() -> str:
18
+ # Prefer an explicit path from the launcher/daemon.
19
+ explicit = os.environ.get("FLOCKBAY_UNREAL_MCP_LOG_PATH", "").strip()
20
+ if explicit:
21
+ return explicit
22
+
23
+ # Fall back to a writable per-user folder.
24
+ home = os.environ.get("FLOCKBAY_HOME_DIR", "").strip()
25
+ if not home:
26
+ home = os.path.join(os.path.expanduser("~"), ".flockbay")
27
+
28
+ runtime_dir = os.path.join(home, "unreal-mcp")
29
+ try:
30
+ os.makedirs(runtime_dir, exist_ok=True)
31
+ except Exception:
32
+ # Last resort: current working directory (may fail on locked installs).
33
+ return "unreal_mcp.log"
34
+
35
+ return os.path.join(runtime_dir, "unreal_mcp.log")
36
+
37
+ logging.basicConfig(
38
+ level=logging.DEBUG, # Change to DEBUG level for more details
39
+ format='%(asctime)s - %(name)s - %(levelname)s - [%(filename)s:%(lineno)d] - %(message)s',
40
+ handlers=[
41
+ logging.FileHandler(_default_log_path()),
42
+ # logging.StreamHandler(sys.stdout) # Remove this handler to unexpected non-whitespace characters in JSON
43
+ ]
44
+ )
45
+ logger = logging.getLogger("UnrealMCP")
46
+
47
+ # Configuration
48
+ UNREAL_HOST = "127.0.0.1"
49
+ UNREAL_PORT = 55557
50
+
51
+ class UnrealConnection:
52
+ """Connection to an Unreal Engine instance."""
53
+
54
+ def __init__(self):
55
+ """Initialize the connection."""
56
+ self.socket = None
57
+ self.connected = False
58
+
59
+ def connect(self) -> bool:
60
+ """Connect to the Unreal Engine instance."""
61
+ try:
62
+ # Close any existing socket
63
+ if self.socket:
64
+ try:
65
+ self.socket.close()
66
+ except:
67
+ pass
68
+ self.socket = None
69
+
70
+ logger.info(f"Connecting to Unreal at {UNREAL_HOST}:{UNREAL_PORT}...")
71
+ self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
72
+ self.socket.settimeout(5) # 5 second timeout
73
+
74
+ # Set socket options for better stability
75
+ self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
76
+ self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
77
+
78
+ # Set larger buffer sizes
79
+ self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 65536)
80
+ self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 65536)
81
+
82
+ self.socket.connect((UNREAL_HOST, UNREAL_PORT))
83
+ self.connected = True
84
+ logger.info("Connected to Unreal Engine")
85
+ return True
86
+
87
+ except Exception as e:
88
+ logger.error(f"Failed to connect to Unreal: {e}")
89
+ self.connected = False
90
+ return False
91
+
92
+ def disconnect(self):
93
+ """Disconnect from the Unreal Engine instance."""
94
+ if self.socket:
95
+ try:
96
+ self.socket.close()
97
+ except:
98
+ pass
99
+ self.socket = None
100
+ self.connected = False
101
+
102
+ def receive_full_response(self, sock, buffer_size=4096) -> bytes:
103
+ """Receive a complete response from Unreal, handling chunked data."""
104
+ chunks = []
105
+ sock.settimeout(5) # 5 second timeout
106
+ try:
107
+ while True:
108
+ chunk = sock.recv(buffer_size)
109
+ if not chunk:
110
+ if not chunks:
111
+ raise Exception("Connection closed before receiving data")
112
+ break
113
+ chunks.append(chunk)
114
+
115
+ # Process the data received so far
116
+ data = b''.join(chunks)
117
+ decoded_data = data.decode('utf-8')
118
+
119
+ # Try to parse as JSON to check if complete
120
+ try:
121
+ json.loads(decoded_data)
122
+ logger.info(f"Received complete response ({len(data)} bytes)")
123
+ return data
124
+ except json.JSONDecodeError:
125
+ # Not complete JSON yet, continue reading
126
+ logger.debug(f"Received partial response, waiting for more data...")
127
+ continue
128
+ except Exception as e:
129
+ logger.warning(f"Error processing response chunk: {str(e)}")
130
+ continue
131
+ except socket.timeout:
132
+ logger.warning("Socket timeout during receive")
133
+ if chunks:
134
+ # If we have some data already, try to use it
135
+ data = b''.join(chunks)
136
+ try:
137
+ json.loads(data.decode('utf-8'))
138
+ logger.info(f"Using partial response after timeout ({len(data)} bytes)")
139
+ return data
140
+ except:
141
+ pass
142
+ raise Exception("Timeout receiving Unreal response")
143
+ except Exception as e:
144
+ logger.error(f"Error during receive: {str(e)}")
145
+ raise
146
+
147
+ def send_command(self, command: str, params: Dict[str, Any] = None) -> Optional[Dict[str, Any]]:
148
+ """Send a command to Unreal Engine and get the response."""
149
+ # Always reconnect for each command, since Unreal closes the connection after each command
150
+ # This is different from Unity which keeps connections alive
151
+ if self.socket:
152
+ try:
153
+ self.socket.close()
154
+ except:
155
+ pass
156
+ self.socket = None
157
+ self.connected = False
158
+
159
+ if not self.connect():
160
+ logger.error("Failed to connect to Unreal Engine for command")
161
+ return None
162
+
163
+ try:
164
+ # Match Unity's command format exactly
165
+ command_obj = {
166
+ "type": command, # Use "type" instead of "command"
167
+ "params": params or {} # Use Unity's params or {} pattern
168
+ }
169
+
170
+ # Send without newline, exactly like Unity
171
+ command_json = json.dumps(command_obj)
172
+ logger.info(f"Sending command: {command_json}")
173
+ self.socket.sendall(command_json.encode('utf-8'))
174
+
175
+ # Read response using improved handler
176
+ response_data = self.receive_full_response(self.socket)
177
+ response = json.loads(response_data.decode('utf-8'))
178
+
179
+ # Log complete response for debugging
180
+ logger.info(f"Complete response from Unreal: {response}")
181
+
182
+ # Check for both error formats: {"status": "error", ...} and {"success": false, ...}
183
+ if response.get("status") == "error":
184
+ error_message = response.get("error") or response.get("message", "Unknown Unreal error")
185
+ logger.error(f"Unreal error (status=error): {error_message}")
186
+ # We want to preserve the original error structure but ensure error is accessible
187
+ if "error" not in response:
188
+ response["error"] = error_message
189
+ elif response.get("success") is False:
190
+ # This format uses {"success": false, "error": "message"} or {"success": false, "message": "message"}
191
+ error_message = response.get("error") or response.get("message", "Unknown Unreal error")
192
+ logger.error(f"Unreal error (success=false): {error_message}")
193
+ # Convert to the standard format expected by higher layers
194
+ response = {
195
+ "status": "error",
196
+ "error": error_message
197
+ }
198
+
199
+ # Always close the connection after command is complete
200
+ # since Unreal will close it on its side anyway
201
+ try:
202
+ self.socket.close()
203
+ except:
204
+ pass
205
+ self.socket = None
206
+ self.connected = False
207
+
208
+ return response
209
+
210
+ except Exception as e:
211
+ logger.error(f"Error sending command: {e}")
212
+ # Always reset connection state on any error
213
+ self.connected = False
214
+ try:
215
+ self.socket.close()
216
+ except:
217
+ pass
218
+ self.socket = None
219
+ return {
220
+ "status": "error",
221
+ "error": str(e)
222
+ }
223
+
224
+ # Global connection state
225
+ _unreal_connection: UnrealConnection = None
226
+
227
+ def get_unreal_connection() -> Optional[UnrealConnection]:
228
+ """Get the connection to Unreal Engine."""
229
+ global _unreal_connection
230
+ try:
231
+ if _unreal_connection is None:
232
+ _unreal_connection = UnrealConnection()
233
+ if not _unreal_connection.connect():
234
+ logger.warning("Could not connect to Unreal Engine")
235
+ _unreal_connection = None
236
+ else:
237
+ # Verify connection is still valid with a ping-like test
238
+ try:
239
+ # Simple test by sending an empty buffer to check if socket is still connected
240
+ _unreal_connection.socket.sendall(b'\x00')
241
+ logger.debug("Connection verified with ping test")
242
+ except Exception as e:
243
+ logger.warning(f"Existing connection failed: {e}")
244
+ _unreal_connection.disconnect()
245
+ _unreal_connection = None
246
+ # Try to reconnect
247
+ _unreal_connection = UnrealConnection()
248
+ if not _unreal_connection.connect():
249
+ logger.warning("Could not reconnect to Unreal Engine")
250
+ _unreal_connection = None
251
+ else:
252
+ logger.info("Successfully reconnected to Unreal Engine")
253
+
254
+ return _unreal_connection
255
+ except Exception as e:
256
+ logger.error(f"Error getting Unreal connection: {e}")
257
+ return None
258
+
259
+ @asynccontextmanager
260
+ async def server_lifespan(server: FastMCP) -> AsyncIterator[Dict[str, Any]]:
261
+ """Handle server startup and shutdown."""
262
+ global _unreal_connection
263
+ logger.info("UnrealMCP server starting up")
264
+ try:
265
+ _unreal_connection = get_unreal_connection()
266
+ if _unreal_connection:
267
+ logger.info("Connected to Unreal Engine on startup")
268
+ else:
269
+ logger.warning("Could not connect to Unreal Engine on startup")
270
+ except Exception as e:
271
+ logger.error(f"Error connecting to Unreal Engine on startup: {e}")
272
+ _unreal_connection = None
273
+
274
+ try:
275
+ yield {}
276
+ finally:
277
+ if _unreal_connection:
278
+ _unreal_connection.disconnect()
279
+ _unreal_connection = None
280
+ logger.info("Unreal MCP server shut down")
281
+
282
+ # Initialize server
283
+ mcp = FastMCP(
284
+ "UnrealMCP",
285
+ description="Unreal Engine integration via Model Context Protocol",
286
+ lifespan=server_lifespan
287
+ )
288
+
289
+ # Import and register tools
290
+ from tools.editor_tools import register_editor_tools
291
+ from tools.blueprint_tools import register_blueprint_tools
292
+ from tools.node_tools import register_blueprint_node_tools
293
+ from tools.project_tools import register_project_tools
294
+ from tools.umg_tools import register_umg_tools
295
+
296
+ # Register tools
297
+ register_editor_tools(mcp)
298
+ register_blueprint_tools(mcp)
299
+ register_blueprint_node_tools(mcp)
300
+ register_project_tools(mcp)
301
+ register_umg_tools(mcp)
302
+
303
+ @mcp.prompt()
304
+ def info():
305
+ """Information about available Unreal MCP tools and best practices."""
306
+ return """
307
+ # Unreal MCP Server Tools and Best Practices
308
+
309
+ ## UMG (Widget Blueprint) Tools
310
+ - `create_umg_widget_blueprint(widget_name, parent_class="UserWidget", path="/Game/UI")`
311
+ Create a new UMG Widget Blueprint
312
+ - `add_text_block_to_widget(widget_name, text_block_name, text="", position=[0,0], size=[200,50], font_size=12, color=[1,1,1,1])`
313
+ Add a Text Block widget with customizable properties
314
+ - `add_button_to_widget(widget_name, button_name, text="", position=[0,0], size=[200,50], font_size=12, color=[1,1,1,1], background_color=[0.1,0.1,0.1,1])`
315
+ Add a Button widget with text and styling
316
+ - `bind_widget_event(widget_name, widget_component_name, event_name, function_name="")`
317
+ Bind events like OnClicked to functions
318
+ - `add_widget_to_viewport(widget_name, z_order=0)`
319
+ Add widget instance to game viewport
320
+ - `set_text_block_binding(widget_name, text_block_name, binding_property, binding_type="Text")`
321
+ Set up dynamic property binding for text blocks
322
+
323
+ ## Editor Tools
324
+ ### Viewport and Screenshots
325
+ - `focus_viewport(target, location, distance, orientation)` - Focus viewport
326
+ - `take_screenshot(filename, show_ui, resolution)` - Capture screenshots
327
+
328
+ ### Actor Management
329
+ - `get_actors_in_level()` - List all actors in current level
330
+ - `find_actors_by_name(pattern)` - Find actors by name pattern
331
+ - `spawn_actor(name, type, location=[0,0,0], rotation=[0,0,0], scale=[1,1,1])` - Create actors
332
+ - `delete_actor(name)` - Remove actors
333
+ - `set_actor_transform(name, location, rotation, scale)` - Modify actor transform
334
+ - `get_actor_properties(name)` - Get actor properties
335
+
336
+ ## Blueprint Management
337
+ - `create_blueprint(name, parent_class)` - Create new Blueprint classes
338
+ - `add_component_to_blueprint(blueprint_name, component_type, component_name)` - Add components
339
+ - `set_static_mesh_properties(blueprint_name, component_name, static_mesh)` - Configure meshes
340
+ - `set_physics_properties(blueprint_name, component_name)` - Configure physics
341
+ - `compile_blueprint(blueprint_name)` - Compile Blueprint changes
342
+ - `set_blueprint_property(blueprint_name, property_name, property_value)` - Set properties
343
+ - `set_pawn_properties(blueprint_name)` - Configure Pawn settings
344
+ - `spawn_blueprint_actor(blueprint_name, actor_name)` - Spawn Blueprint actors
345
+
346
+ ## Blueprint Node Management
347
+ - `add_blueprint_event_node(blueprint_name, event_type)` - Add event nodes
348
+ - `add_blueprint_input_action_node(blueprint_name, action_name)` - Add input nodes
349
+ - `add_blueprint_function_node(blueprint_name, target, function_name)` - Add function nodes
350
+ - `connect_blueprint_nodes(blueprint_name, source_node_id, source_pin, target_node_id, target_pin)` - Connect nodes
351
+ - `add_blueprint_variable(blueprint_name, variable_name, variable_type)` - Add variables
352
+ - `add_blueprint_get_self_component_reference(blueprint_name, component_name)` - Add component refs
353
+ - `add_blueprint_self_reference(blueprint_name)` - Add self references
354
+ - `find_blueprint_nodes(blueprint_name, node_type, event_type)` - Find nodes
355
+
356
+ ## Project Tools
357
+ - `create_input_mapping(action_name, key, input_type)` - Create input mappings
358
+
359
+ ## Best Practices
360
+
361
+ ### UMG Widget Development
362
+ - Create widgets with descriptive names that reflect their purpose
363
+ - Use consistent naming conventions for widget components
364
+ - Organize widget hierarchy logically
365
+ - Set appropriate anchors and alignment for responsive layouts
366
+ - Use property bindings for dynamic updates instead of direct setting
367
+ - Handle widget events appropriately with meaningful function names
368
+ - Clean up widgets when no longer needed
369
+ - Test widget layouts at different resolutions
370
+
371
+ ### Editor and Actor Management
372
+ - Use unique names for actors to avoid conflicts
373
+ - Clean up temporary actors
374
+ - Validate transforms before applying
375
+ - Check actor existence before modifications
376
+ - Take regular viewport screenshots during development
377
+ - Keep the viewport focused on relevant actors during operations
378
+
379
+ ### Blueprint Development
380
+ - Compile Blueprints after changes
381
+ - Use meaningful names for variables and functions
382
+ - Organize nodes logically
383
+ - Test functionality in isolation
384
+ - Consider performance implications
385
+ - Document complex setups
386
+
387
+ ### Error Handling
388
+ - Check command responses for success
389
+ - Handle errors gracefully
390
+ - Log important operations
391
+ - Validate parameters
392
+ - Clean up resources on errors
393
+ """
394
+
395
+ # Run the server
396
+ if __name__ == "__main__":
397
+ logger.info("Starting MCP server with stdio transport")
398
+ mcp.run(transport='stdio')