using System.Collections.Generic;
namespace io.github.hatayama.uLoopMCP
{
///
/// 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)
///
public static class McpServerConfigFactory
{
///
/// Creates Unity MCP server configuration.
///
/// The port number to use.
/// The path to the TypeScript server.
/// The editor type for client name.
/// Settings data for Unity MCP.
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 env = new Dictionary
{
{ 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
);
}
///
/// Get appropriate server path based on editor type
///
/// The original server path
/// The editor type
/// The processed server path
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);
}
///
/// Convert absolute path to relative path for all editors
///
/// The absolute path to convert
/// The relative path from project root
private static string ConvertToRelativePath(string absolutePath)
{
return UnityMcpPathResolver.MakeRelativeToConfigurationRoot(absolutePath);
}
///
/// Creates Unity MCP server configuration (legacy overload for backward compatibility).
///
/// The port number to use.
/// The path to the TypeScript server.
/// Settings data for Unity MCP.
public static McpServerConfigData CreateUnityMcpConfig(int port, string serverPath)
{
return CreateUnityMcpConfig(port, serverPath, McpEditorType.ClaudeCode);
}
///
/// Creates Unity MCP server configuration with development mode support.
///
/// The port number.
/// The path to the TypeScript server.
/// Whether to enable development mode.
/// Settings data for Unity MCP.
public static McpServerConfigData CreateUnityMcpConfigWithDevelopmentMode(int port, string serverPath, bool developmentMode)
{
Dictionary env = new Dictionary
{
{ 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
);
}
///
/// Creates Unity MCP server key.
///
/// The port number.
/// The server key.
public static string CreateUnityMcpServerKey(int port)
{
return $"{McpConstants.PROJECT_NAME}-{port}";
}
///
/// Creates Unity MCP server key with editor type consideration.
///
/// The port number.
/// The editor type.
/// The server key.
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;
}
}
}