更新 maya_mcp_plugin.py
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Maya MCP Plugin
|
||||
This plugin provides integration with the Model Context Protocol for Maya.
|
||||
@@ -16,6 +19,8 @@ import os
|
||||
import maya.api.OpenMaya as om
|
||||
import maya.cmds as cmds
|
||||
import traceback
|
||||
import time
|
||||
import inspect
|
||||
|
||||
# Plugin information
|
||||
def maya_useNewAPI():
|
||||
@@ -24,6 +29,320 @@ def maya_useNewAPI():
|
||||
"""
|
||||
pass
|
||||
|
||||
# Global variables
|
||||
_mcp_menu = None
|
||||
|
||||
def create_menu():
|
||||
"""
|
||||
Create the MCP menu in Maya
|
||||
|
||||
Returns:
|
||||
str: Menu name if created successfully, None otherwise
|
||||
"""
|
||||
global _mcp_menu
|
||||
|
||||
try:
|
||||
# Delete existing menu if it exists
|
||||
if _mcp_menu and cmds.menu(_mcp_menu, exists=True):
|
||||
cmds.deleteUI(_mcp_menu)
|
||||
|
||||
# Get main window
|
||||
main_window = "MayaWindow"
|
||||
|
||||
# Create menu
|
||||
_mcp_menu = cmds.menu("MCPMenu", label="MCP", parent=main_window)
|
||||
|
||||
# Add menu items
|
||||
cmds.menuItem(label="Start Server", command=lambda x: start_server_cmd())
|
||||
cmds.menuItem(label="Stop Server", command=lambda x: stop_server_cmd())
|
||||
cmds.menuItem(label="Restart Server", command=lambda x: restart_server_cmd())
|
||||
cmds.menuItem(divider=True)
|
||||
cmds.menuItem(label="Configure Port", command=lambda x: configure_port_cmd())
|
||||
cmds.menuItem(divider=True)
|
||||
cmds.menuItem(label="About", command=lambda x: about_cmd())
|
||||
|
||||
om.MGlobal.displayInfo("MCP menu created successfully")
|
||||
return _mcp_menu
|
||||
except Exception as e:
|
||||
om.MGlobal.displayError(f"Error creating MCP menu: {e}")
|
||||
return None
|
||||
|
||||
def start_server_cmd(*args):
|
||||
"""Command to start the MCP server"""
|
||||
try:
|
||||
import server
|
||||
|
||||
if server.is_server_running():
|
||||
cmds.confirmDialog(
|
||||
title="MCP Server",
|
||||
message="MCP server is already running",
|
||||
button="OK"
|
||||
)
|
||||
return
|
||||
|
||||
port = server.start_server()
|
||||
|
||||
if port:
|
||||
cmds.inViewMessage(
|
||||
message=f"MCP server started on port {port}",
|
||||
position="topCenter",
|
||||
fade=True,
|
||||
fadeOutTime=5.0,
|
||||
backColor=(0.2, 0.6, 0.2),
|
||||
fontSize=24
|
||||
)
|
||||
else:
|
||||
cmds.confirmDialog(
|
||||
title="MCP Server Error",
|
||||
message="Failed to start MCP server",
|
||||
button="OK"
|
||||
)
|
||||
except Exception as e:
|
||||
error_msg = f"Error starting MCP server: {e}"
|
||||
om.MGlobal.displayError(error_msg)
|
||||
cmds.confirmDialog(
|
||||
title="MCP Server Error",
|
||||
message=error_msg,
|
||||
button="OK"
|
||||
)
|
||||
|
||||
def stop_server_cmd(*args):
|
||||
"""Command to stop the MCP server"""
|
||||
try:
|
||||
import server
|
||||
|
||||
if not server.is_server_running():
|
||||
cmds.confirmDialog(
|
||||
title="MCP Server",
|
||||
message="MCP server is not running",
|
||||
button="OK"
|
||||
)
|
||||
return
|
||||
|
||||
success = server.stop_server()
|
||||
|
||||
if success:
|
||||
cmds.inViewMessage(
|
||||
message="MCP server stopped",
|
||||
position="topCenter",
|
||||
fade=True,
|
||||
fadeOutTime=5.0,
|
||||
backColor=(0.6, 0.2, 0.2),
|
||||
fontSize=24
|
||||
)
|
||||
else:
|
||||
cmds.confirmDialog(
|
||||
title="MCP Server Error",
|
||||
message="Failed to stop MCP server",
|
||||
button="OK"
|
||||
)
|
||||
except Exception as e:
|
||||
error_msg = f"Error stopping MCP server: {e}"
|
||||
om.MGlobal.displayError(error_msg)
|
||||
cmds.confirmDialog(
|
||||
title="MCP Server Error",
|
||||
message=error_msg,
|
||||
button="OK"
|
||||
)
|
||||
|
||||
def restart_server_cmd(*args):
|
||||
"""Command to restart the MCP server"""
|
||||
try:
|
||||
import server
|
||||
|
||||
# Stop the server
|
||||
om.MGlobal.displayInfo("Stopping MCP server...")
|
||||
server.stop_server()
|
||||
|
||||
# Wait for a moment to ensure the server is fully stopped
|
||||
time.sleep(1)
|
||||
|
||||
# Start the server
|
||||
om.MGlobal.displayInfo("Starting MCP server...")
|
||||
port = server.start_server()
|
||||
|
||||
if port:
|
||||
cmds.inViewMessage(
|
||||
message=f"MCP server restarted on port {port}",
|
||||
position="topCenter",
|
||||
fade=True,
|
||||
fadeOutTime=5.0,
|
||||
backColor=(0.2, 0.6, 0.2),
|
||||
fontSize=24
|
||||
)
|
||||
om.MGlobal.displayInfo(f"MCP server successfully restarted on port {port}")
|
||||
else:
|
||||
cmds.confirmDialog(
|
||||
title="MCP Server Error",
|
||||
message="Failed to restart MCP server",
|
||||
button="OK"
|
||||
)
|
||||
om.MGlobal.displayError("Failed to restart MCP server")
|
||||
except Exception as e:
|
||||
error_msg = f"Error restarting MCP server: {e}"
|
||||
om.MGlobal.displayError(error_msg)
|
||||
cmds.confirmDialog(
|
||||
title="MCP Server Error",
|
||||
message=error_msg,
|
||||
button="OK"
|
||||
)
|
||||
|
||||
def configure_port_cmd(*args):
|
||||
"""Command to configure server port"""
|
||||
try:
|
||||
# Import port_config to get current port
|
||||
import port_config
|
||||
current_port = port_config.SERVER_PORT
|
||||
|
||||
# Show dialog to input new port
|
||||
result = cmds.promptDialog(
|
||||
title='Configure MCP Port',
|
||||
message='Enter new port number:',
|
||||
text=str(current_port),
|
||||
button=['OK', 'Cancel'],
|
||||
defaultButton='OK',
|
||||
cancelButton='Cancel',
|
||||
dismissString='Cancel'
|
||||
)
|
||||
|
||||
if result == 'OK':
|
||||
# Get the new port number
|
||||
new_port_str = cmds.promptDialog(query=True, text=True)
|
||||
|
||||
try:
|
||||
new_port = int(new_port_str)
|
||||
|
||||
# Validate port number
|
||||
if new_port < 1024 or new_port > 65535:
|
||||
cmds.confirmDialog(
|
||||
title="Invalid Port",
|
||||
message="Port number must be between 1024 and 65535",
|
||||
button="OK"
|
||||
)
|
||||
return
|
||||
|
||||
# Get the plugin path using a more reliable method
|
||||
import sys
|
||||
plugin_path = None
|
||||
for path in sys.path:
|
||||
if path.endswith('MayaMCP') and os.path.exists(path):
|
||||
plugin_path = path
|
||||
break
|
||||
|
||||
if not plugin_path:
|
||||
# Fallback to a hardcoded path if needed
|
||||
plugin_path = "D:/Dev/Tools/MayaMCP"
|
||||
if not os.path.exists(plugin_path):
|
||||
raise Exception(f"Could not find plugin path: {plugin_path}")
|
||||
|
||||
om.MGlobal.displayInfo(f"Using plugin path: {plugin_path}")
|
||||
|
||||
# Update port_config.py file
|
||||
port_config_path = os.path.join(plugin_path, "port_config.py")
|
||||
om.MGlobal.displayInfo(f"Port config path: {port_config_path}")
|
||||
|
||||
# Read the current content
|
||||
with open(port_config_path, 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
# Replace the port number
|
||||
import re
|
||||
new_content = re.sub(
|
||||
r'SERVER_PORT\s*=\s*\d+',
|
||||
f'SERVER_PORT = {new_port}',
|
||||
content
|
||||
)
|
||||
|
||||
# Write the updated content
|
||||
with open(port_config_path, 'w') as f:
|
||||
f.write(new_content)
|
||||
|
||||
# Reload port_config module to apply changes
|
||||
import importlib
|
||||
if 'port_config' in sys.modules:
|
||||
importlib.reload(sys.modules['port_config'])
|
||||
om.MGlobal.displayInfo("Reloaded port_config module")
|
||||
# Update global variable
|
||||
import port_config
|
||||
port_config.SERVER_PORT = new_port
|
||||
om.MGlobal.displayInfo(f"Updated SERVER_PORT to {port_config.SERVER_PORT}")
|
||||
|
||||
# Ask if user wants to restart the server
|
||||
result = cmds.confirmDialog(
|
||||
title="Port Updated",
|
||||
message=f"Port has been updated to {new_port}.\n\nDo you want to restart the server now?",
|
||||
button=["Yes", "No"],
|
||||
defaultButton="Yes",
|
||||
cancelButton="No",
|
||||
dismissString="No"
|
||||
)
|
||||
|
||||
if result == "Yes":
|
||||
# Stop current server
|
||||
import server
|
||||
om.MGlobal.displayInfo("Stopping current server...")
|
||||
server.stop_server()
|
||||
|
||||
# Wait for server to fully stop
|
||||
time.sleep(2)
|
||||
|
||||
# Reload server module
|
||||
if 'server' in sys.modules:
|
||||
importlib.reload(sys.modules['server'])
|
||||
om.MGlobal.displayInfo("Reloaded server module")
|
||||
|
||||
# Reload http_handler module
|
||||
if 'http_handler' in sys.modules:
|
||||
importlib.reload(sys.modules['http_handler'])
|
||||
om.MGlobal.displayInfo("Reloaded http_handler module")
|
||||
|
||||
# Start server on new port
|
||||
om.MGlobal.displayInfo(f"Starting server on new port {new_port}...")
|
||||
port = server.start_server()
|
||||
|
||||
if port == new_port:
|
||||
cmds.inViewMessage(
|
||||
message=f"MCP server restarted on port {port}",
|
||||
position="topCenter",
|
||||
fade=True,
|
||||
fadeOutTime=5.0,
|
||||
backColor=(0.2, 0.6, 0.2),
|
||||
fontSize=24
|
||||
)
|
||||
om.MGlobal.displayInfo(f"Server successfully restarted on port {port}")
|
||||
else:
|
||||
cmds.confirmDialog(
|
||||
title="Port Mismatch",
|
||||
message=f"Server started on port {port}, but requested port was {new_port}",
|
||||
button="OK"
|
||||
)
|
||||
else:
|
||||
om.MGlobal.displayInfo(f"MCP port updated to {new_port}. Please restart the server manually.")
|
||||
|
||||
except ValueError:
|
||||
cmds.confirmDialog(
|
||||
title="Invalid Input",
|
||||
message="Please enter a valid port number",
|
||||
button="OK"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Error configuring port: {e}"
|
||||
om.MGlobal.displayError(error_msg)
|
||||
cmds.confirmDialog(
|
||||
title="Configuration Error",
|
||||
message=error_msg,
|
||||
button="OK"
|
||||
)
|
||||
|
||||
def about_cmd(*args):
|
||||
"""Command to show about dialog"""
|
||||
cmds.confirmDialog(
|
||||
title="About MCP",
|
||||
message="Maya MCP (Model Context Protocol)\nVersion 1.0.0\n\nAuthor: Jeffrey Tsai",
|
||||
button="OK"
|
||||
)
|
||||
|
||||
# Plugin initialization
|
||||
def initializePlugin(plugin):
|
||||
"""
|
||||
@@ -32,18 +351,31 @@ def initializePlugin(plugin):
|
||||
Args:
|
||||
plugin: MObject used to register commands
|
||||
"""
|
||||
vendor = "Virtuos Games"
|
||||
vendor = "Jeffrey Tsai"
|
||||
version = "1.0.0"
|
||||
|
||||
plugin_fn = om.MFnPlugin(plugin, vendor, version)
|
||||
|
||||
try:
|
||||
# Add the plugin directory to the Python path
|
||||
# Use plugin_fn.loadPath() instead of __file__ to get the plugin path
|
||||
# Get more reliable plugin path
|
||||
plugin_path = os.path.dirname(plugin_fn.loadPath())
|
||||
om.MGlobal.displayInfo(f"Plugin path: {plugin_path}")
|
||||
|
||||
# Make sure the path is added to sys.path
|
||||
# Get MayaMCP directory path - fix the path issue
|
||||
mcp_dir = os.path.join(plugin_path, "MayaMCP")
|
||||
mcp_dir = mcp_dir.replace('\\', '/') # Ensure forward slashes
|
||||
om.MGlobal.displayInfo(f"MayaMCP directory: {mcp_dir}")
|
||||
|
||||
if os.path.exists(mcp_dir):
|
||||
om.MGlobal.displayInfo(f"MayaMCP directory found: {mcp_dir}")
|
||||
# Add MayaMCP directory to sys.path
|
||||
if mcp_dir not in sys.path:
|
||||
sys.path.append(mcp_dir)
|
||||
om.MGlobal.displayInfo(f"Added MayaMCP directory to sys.path: {mcp_dir}")
|
||||
else:
|
||||
om.MGlobal.displayInfo(f"MayaMCP directory not found at: {mcp_dir}")
|
||||
|
||||
# Ensure plugin path is also added to sys.path
|
||||
if plugin_path not in sys.path:
|
||||
sys.path.append(plugin_path)
|
||||
om.MGlobal.displayInfo(f"Added to sys.path: {plugin_path}")
|
||||
@@ -51,26 +383,71 @@ def initializePlugin(plugin):
|
||||
# Print current sys.path for debugging
|
||||
om.MGlobal.displayInfo(f"Current sys.path: {sys.path}")
|
||||
|
||||
# Check if loader.py exists in the plugin directory
|
||||
loader_path = os.path.join(plugin_path, "loader.py")
|
||||
if os.path.exists(loader_path):
|
||||
om.MGlobal.displayInfo(f"loader.py found at: {loader_path}")
|
||||
else:
|
||||
om.MGlobal.displayError(f"loader.py not found at: {loader_path}")
|
||||
# Force reload modules if they are already loaded
|
||||
# This ensures we're using the latest version of the code
|
||||
for module_name in ["server", "http_handler", "maya_mcp"]:
|
||||
if module_name in sys.modules:
|
||||
om.MGlobal.displayInfo(f"Reloading module: {module_name}")
|
||||
try:
|
||||
# Python 3.4+
|
||||
import importlib
|
||||
importlib.reload(sys.modules[module_name])
|
||||
except Exception as e:
|
||||
om.MGlobal.displayWarning(f"Failed to reload module {module_name}: {e}")
|
||||
|
||||
# Import and start MCP server
|
||||
# Directly import required modules, not dependent on loader.py
|
||||
try:
|
||||
# Try to import directly from the plugin path
|
||||
sys.path.insert(0, plugin_path) # Add to the beginning of sys.path
|
||||
# Try to import server module
|
||||
om.MGlobal.displayInfo("Attempting to import server module...")
|
||||
|
||||
# Try to import the module
|
||||
om.MGlobal.displayInfo("Attempting to import loader module...")
|
||||
from loader import auto_load
|
||||
om.MGlobal.displayInfo("Successfully imported loader module")
|
||||
# Add current directory to sys.path
|
||||
# Cannot use __file__ in Maya plugin, use plugin_path instead
|
||||
current_dir = plugin_path
|
||||
if "MayaMCP" in current_dir:
|
||||
current_dir = current_dir # Already in MayaMCP directory
|
||||
else:
|
||||
# Try to find MayaMCP directory
|
||||
mcp_dir = os.path.join(current_dir, "MayaMCP")
|
||||
if os.path.exists(mcp_dir):
|
||||
current_dir = mcp_dir
|
||||
|
||||
# Start the server
|
||||
auto_load()
|
||||
om.MGlobal.displayInfo("MCP server loaded successfully")
|
||||
current_dir = current_dir.replace('\\', '/') # Ensure forward slashes
|
||||
om.MGlobal.displayInfo(f"Using directory: {current_dir}")
|
||||
|
||||
if current_dir not in sys.path:
|
||||
sys.path.insert(0, current_dir)
|
||||
om.MGlobal.displayInfo(f"Added directory to sys.path: {current_dir}")
|
||||
|
||||
# Import server module
|
||||
import server
|
||||
om.MGlobal.displayInfo("Successfully imported server module")
|
||||
|
||||
# Force create menu
|
||||
om.MGlobal.displayInfo("Forcing menu creation...")
|
||||
menu_result = create_menu()
|
||||
if menu_result:
|
||||
om.MGlobal.displayInfo("Menu created successfully")
|
||||
else:
|
||||
om.MGlobal.displayWarning("Menu creation may have failed")
|
||||
|
||||
# Try alternative method to create menu
|
||||
try:
|
||||
# Use a deferred command to create the menu
|
||||
# This gives Maya time to initialize the UI
|
||||
cmds.evalDeferred("import maya_mcp_plugin; maya_mcp_plugin.create_menu()")
|
||||
om.MGlobal.displayInfo("Scheduled deferred menu creation")
|
||||
except Exception as e:
|
||||
om.MGlobal.displayError(f"Failed to schedule deferred menu creation: {e}")
|
||||
|
||||
# Start server
|
||||
port = server.start_server()
|
||||
if port:
|
||||
message = "=" * 50
|
||||
message += "\nMCP SERVER STARTED SUCCESSFULLY ON PORT {}\n".format(port)
|
||||
message += "=" * 50
|
||||
om.MGlobal.displayInfo(message)
|
||||
else:
|
||||
om.MGlobal.displayError("Failed to start MCP server")
|
||||
except Exception as e:
|
||||
om.MGlobal.displayError(f"Failed to load MCP server: {e}")
|
||||
om.MGlobal.displayError(f"Traceback: {traceback.format_exc()}")
|
||||
|
Reference in New Issue
Block a user