159 lines
6.7 KiB
C#
159 lines
6.7 KiB
C#
using System.Collections.Generic;
|
|
|
|
namespace io.github.hatayama.uLoopMCP
|
|
{
|
|
/// <summary>
|
|
/// Factory class for creating MCP server configuration objects.
|
|
/// Single Responsibility Principle: Only responsible for object creation.
|
|
///
|
|
/// Design document reference: Packages/src/Editor/ARCHITECTURE.md
|
|
///
|
|
/// Related classes:
|
|
/// - McpConfigService: Uses this factory to create server configurations
|
|
/// - McpServerConfigData: Value object that this factory creates
|
|
/// - UnityMcpPathResolver: Provides TypeScript server paths and project root
|
|
/// - McpConstants: Contains command constants (NODE_COMMAND) and environment keys
|
|
/// - McpEditorType: Enum defining supported editor types
|
|
///
|
|
/// Key features:
|
|
/// - Creates server configuration with editor-specific path formats (absolute/relative)
|
|
/// - Generates server keys with or without port numbers based on editor type
|
|
/// - Environment variables are minimal (only UNITY_TCP_PORT, no MCP_CLIENT_NAME)
|
|
/// </summary>
|
|
public static class McpServerConfigFactory
|
|
{
|
|
/// <summary>
|
|
/// Creates Unity MCP server configuration.
|
|
/// </summary>
|
|
/// <param name="port">The port number to use.</param>
|
|
/// <param name="serverPath">The path to the TypeScript server.</param>
|
|
/// <param name="editorType">The editor type for client name.</param>
|
|
/// <returns>Settings data for Unity MCP.</returns>
|
|
public static McpServerConfigData CreateUnityMcpConfig(int port, string serverPath, McpEditorType editorType)
|
|
{
|
|
// Convert server path to appropriate format based on editor type
|
|
string finalServerPath = GetServerPathForEditor(serverPath, editorType);
|
|
|
|
Dictionary<string, string> env = new Dictionary<string, string>
|
|
{
|
|
{ McpConstants.UNITY_TCP_PORT_ENV_KEY, port.ToString() }
|
|
// MCP_CLIENT_NAME removed - now using clientInfo.name from MCP protocol
|
|
#if ULOOPMCP_DEBUG
|
|
, { McpConstants.ENV_KEY_MCP_DEBUG, McpConstants.ENV_VALUE_TRUE }
|
|
, { McpConstants.ENV_KEY_NODE_OPTIONS, McpConstants.NODE_OPTIONS_ENABLE_SOURCE_MAPS }
|
|
#endif
|
|
};
|
|
|
|
if (!NodePathResolver.IsNodeAvailable())
|
|
{
|
|
throw new System.InvalidOperationException(
|
|
"Node.js is not available. Ensure Node.js is installed and accessible via PATH.");
|
|
}
|
|
|
|
return new McpServerConfigData(
|
|
command: McpConstants.NODE_COMMAND,
|
|
args: new[] { finalServerPath },
|
|
env: env
|
|
);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get appropriate server path based on editor type
|
|
/// </summary>
|
|
/// <param name="serverPath">The original server path</param>
|
|
/// <param name="editorType">The editor type</param>
|
|
/// <returns>The processed server path</returns>
|
|
private static string GetServerPathForEditor(string serverPath, McpEditorType editorType)
|
|
{
|
|
// Desktop editors (Cursor, VSCode, Windsurf) require absolute path for proper connection
|
|
if (editorType == McpEditorType.Cursor ||
|
|
editorType == McpEditorType.VSCode ||
|
|
editorType == McpEditorType.Windsurf)
|
|
{
|
|
return serverPath;
|
|
}
|
|
|
|
// CLI / project-level editors (Claude Code, Gemini CLI, Codex) use relative path for better portability
|
|
return ConvertToRelativePath(serverPath);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convert absolute path to relative path for all editors
|
|
/// </summary>
|
|
/// <param name="absolutePath">The absolute path to convert</param>
|
|
/// <returns>The relative path from project root</returns>
|
|
private static string ConvertToRelativePath(string absolutePath)
|
|
{
|
|
return UnityMcpPathResolver.MakeRelativeToConfigurationRoot(absolutePath);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates Unity MCP server configuration (legacy overload for backward compatibility).
|
|
/// </summary>
|
|
/// <param name="port">The port number to use.</param>
|
|
/// <param name="serverPath">The path to the TypeScript server.</param>
|
|
/// <returns>Settings data for Unity MCP.</returns>
|
|
public static McpServerConfigData CreateUnityMcpConfig(int port, string serverPath)
|
|
{
|
|
return CreateUnityMcpConfig(port, serverPath, McpEditorType.ClaudeCode);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates Unity MCP server configuration with development mode support.
|
|
/// </summary>
|
|
/// <param name="port">The port number.</param>
|
|
/// <param name="serverPath">The path to the TypeScript server.</param>
|
|
/// <param name="developmentMode">Whether to enable development mode.</param>
|
|
/// <returns>Settings data for Unity MCP.</returns>
|
|
public static McpServerConfigData CreateUnityMcpConfigWithDevelopmentMode(int port, string serverPath, bool developmentMode)
|
|
{
|
|
Dictionary<string, string> env = new Dictionary<string, string>
|
|
{
|
|
{ McpConstants.UNITY_TCP_PORT_ENV_KEY, port.ToString() }
|
|
#if ULOOPMCP_DEBUG
|
|
, { McpConstants.ENV_KEY_MCP_DEBUG, McpConstants.ENV_VALUE_TRUE }
|
|
#endif
|
|
};
|
|
|
|
if (!NodePathResolver.IsNodeAvailable())
|
|
{
|
|
throw new System.InvalidOperationException(
|
|
"Node.js is not available. Ensure Node.js is installed and accessible via PATH.");
|
|
}
|
|
|
|
return new McpServerConfigData(
|
|
command: McpConstants.NODE_COMMAND,
|
|
args: new[] { serverPath },
|
|
env: env
|
|
);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates Unity MCP server key.
|
|
/// </summary>
|
|
/// <param name="port">The port number.</param>
|
|
/// <returns>The server key.</returns>
|
|
public static string CreateUnityMcpServerKey(int port)
|
|
{
|
|
return $"{McpConstants.PROJECT_NAME}-{port}";
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates Unity MCP server key with editor type consideration.
|
|
/// </summary>
|
|
/// <param name="port">The port number.</param>
|
|
/// <param name="editorType">The editor type.</param>
|
|
/// <returns>The server key.</returns>
|
|
public static string CreateUnityMcpServerKey(int port, McpEditorType editorType)
|
|
{
|
|
// Windsurf keeps the port number in the key
|
|
if (editorType == McpEditorType.Windsurf)
|
|
{
|
|
return $"{McpConstants.PROJECT_NAME}-{port}";
|
|
}
|
|
// Other editors use simple key without port
|
|
return McpConstants.PROJECT_NAME;
|
|
}
|
|
|
|
}
|
|
} |