/* ┌──────────────────────────────────────────────────────────────────┐ │ Author: Ivan Murzak (https://github.com/IvanMurzak) │ │ Repository: GitHub (https://github.com/IvanMurzak/Unity-MCP) │ │ Copyright (c) 2025 Ivan Murzak │ │ Licensed under the Apache License, Version 2.0. │ │ See the LICENSE file in the project root for more information. │ └──────────────────────────────────────────────────────────────────┘ */ #nullable enable using System; using System.Collections.Generic; using System.Linq; using System.Text.Json.Nodes; using com.IvanMurzak.McpPlugin; using com.IvanMurzak.ReflectorNet.Utils; using com.IvanMurzak.Unity.MCP.Editor.Utils; using Extensions.Unity.PlayerPrefsEx; using Microsoft.Extensions.Logging; using R3; using UnityEngine.UIElements; namespace com.IvanMurzak.Unity.MCP.Editor.UI { public class McpToolsWindow : McpListWindowBase { private static readonly string[] _windowUxmlPaths = EditorAssetLoader.GetEditorAssetPaths("Editor/UI/uxml/McpToolsWindow.uxml"); private static readonly string[] _itemUxmlPaths = EditorAssetLoader.GetEditorAssetPaths("Editor/UI/uxml/ToolItem.uxml"); private static readonly string[] _windowUssPaths = EditorAssetLoader.GetEditorAssetPaths("Editor/UI/uss/McpToolsWindow.uss"); protected override string[] WindowUxmlPaths => _windowUxmlPaths; protected override string[] ItemUxmlPaths => _itemUxmlPaths; protected override string[] WindowUssPaths => _windowUssPaths; protected override string WindowTitle => "MCP Tools"; protected override string MissingTemplateMessage => "ToolItem template is missing. Please ensure ToolItem.uxml exists in the package or the Packages/com.ivanmurzak.unity.mcp folder."; public static McpToolsWindow ShowWindow() { var window = GetWindow("MCP Tools"); window.SetupWindowWithIcon(); window.Show(); window.Focus(); return window; } protected override Observable? GetOnUpdatedObservable(IMcpPlugin plugin) => plugin.McpManager.ToolManager?.OnToolsUpdated; protected override void RefreshItems() { var toolManager = UnityMcpPluginEditor.Instance.Tools; var refreshed = new List(); if (toolManager != null) { foreach (var tool in toolManager.GetAllTools().Where(tool => tool != null)) { refreshed.Add(new ToolViewModel(toolManager, tool)); } } allItems = refreshed; } protected override void OnItemToggleChanged(ToolViewModel viewModel, bool isEnabled) { var toolManager = UnityMcpPluginEditor.Instance.Tools; if (toolManager == null) { Logger.LogError("{method} ToolManager is not available.", nameof(OnItemToggleChanged)); return; } viewModel.IsEnabled = isEnabled; if (!string.IsNullOrWhiteSpace(viewModel.Name)) { Logger.LogTrace("{method} Setting tool '{name}' enabled state to {enabled}.", nameof(OnItemToggleChanged), viewModel.Name, isEnabled); toolManager.SetToolEnabled(viewModel.Name, isEnabled); UnityMcpPluginEditor.Instance.Save(); } } protected override void OnFoldoutChanged(ToolViewModel viewModel, string foldoutName, bool isExpanded) { switch (foldoutName) { case "description-foldout": viewModel.descriptionExpanded.Value = isExpanded; break; case "arguments-foldout": viewModel.inputsExpanded.Value = isExpanded; break; case "outputs-foldout": viewModel.outputsExpanded.Value = isExpanded; break; } } protected override void BindItem(VisualElement element, ToolViewModel viewModel) { BindCommonItemFields(element, viewModel); BindDescriptionFoldout(element, viewModel, viewModel.descriptionExpanded.Value); // Bind token count var tokenCountLabel = element.Q