Editor/Commands/Tools/GetComponentsTool.cs
using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Threading.Tasks;
using Editor;
using Sandbox;
namespace Braxnet.Commands.Tools;
[MCPTool( "get_components", "Get Components",
"Get all components of a GameObject" )]
public class GetComponentsTool : IMCPTool
{
public string Name => "get_components";
public string Title => "Get Components";
public string Description => "Get all components of a GameObject";
public JsonElement InputSchema => JsonSerializer.SerializeToElement( new
{
type = "object",
properties = new { gameObjectId = new { type = "string", description = "ID of the GameObject" }, },
required = new[] { "gameObjectId" }
} );
public JsonElement OutputSchema => default;
public async Task<CallToolResult> ExecuteAsync( Dictionary<string, object> arguments, string sessionId )
{
var result = new CallToolResult();
if ( arguments == null )
{
result.IsError = true;
result.Content.Add( new TextContent { Text = "No arguments provided" } );
return result;
}
var gameObjectIdStr = arguments.GetValueOrDefault( "gameObjectId" )?.ToString();
if ( string.IsNullOrEmpty( gameObjectIdStr ) )
{
result.IsError = true;
result.Content.Add( new TextContent { Text = "GameObject ID is required" } );
return result;
}
try
{
if ( !Guid.TryParse( gameObjectIdStr, out var gameObjectId ) )
{
result.IsError = true;
result.Content.Add( new TextContent { Text = "Invalid GameObject ID format" } );
return result;
}
// await GameTask.MainThread(); // Ensure this runs on the main thread
var gameObject = SceneEditorSession.Active.Scene.Directory.FindByGuid( gameObjectId );
if ( gameObject == null )
{
result.IsError = true;
result.Content.Add( new TextContent { Text = $"GameObject not found: {gameObjectId}" } );
return result;
}
var components = gameObject.Components.GetAll<Component>( FindMode.EverythingInSelfAndDescendants );
/*var componentList = components.Select( c => new { id = c.Id, type = c.GetType().FullName, name = c. } )
.ToList();*/
var componentList = new List<ComponentInfo>();
foreach ( var component in components )
{
var typeDescription = EditorTypeLibrary.GetType( component.GetType() );
if ( typeDescription == null )
{
result.IsError = true;
result.Content.Add( new TextContent { Text = $"Component type not found: {component.GetType()}" } );
return result;
}
var name = typeDescription?.Name ?? component.GetType().Name;
var properties = new Dictionary<string, string>();
var propertyAttributes = TypeLibrary.GetPropertyDescriptions( component );
foreach ( var p in propertyAttributes )
{
if ( !p.HasAttribute<PropertyAttribute>() ) continue;
try
{
var value = p.GetValue( component );
if ( value != null )
{
properties[p.Name] = value.ToString();
}
}
catch ( Exception ex )
{
properties[p.Name] = $"Error getting value: {ex.Message}";
}
}
var componentInfo = new ComponentInfo
{
Id = component.Id, Type = component.GetType().FullName, Name = name, Properties = properties
};
componentList.Add( componentInfo );
}
result.Content.Add( new TextContent { Text = $"Found {componentList.Count} components" } );
result.StructuredContent = new { gameObjectId = gameObject.Id, components = componentList };
}
catch ( Exception ex )
{
result.IsError = true;
result.Content.Add( new TextContent { Text = $"Error getting components: {ex.Message}" } );
}
return result;
}
public class ComponentInfo
{
public Guid Id { get; set; }
public string Type { get; set; }
public string Name { get; set; }
public Dictionary<string, string> Properties { get; set; } = new();
}
}