更新 maya_mcp_plugin.py

This commit is contained in:
2025-04-16 22:55:21 +08:00
parent eabbddf9b1
commit c64400805e

View File

@@ -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()}")