Add get_component action to manage_gameobject

Adds a new 'get_component' action that retrieves a single component's
serialized data instead of all components, improving efficiency and
avoiding token limits when only specific component data is needed.
main
David Sarno 2025-09-29 20:33:58 -07:00
parent 1ad8c6e504
commit a435973f78
2 changed files with 78 additions and 2 deletions

View File

@ -155,6 +155,18 @@ namespace MCPForUnity.Editor.Tools
);
// Pass the includeNonPublicSerialized flag here
return GetComponentsFromTarget(getCompTarget, searchMethod, includeNonPublicSerialized);
case "get_component":
string getSingleCompTarget = targetToken?.ToString();
if (getSingleCompTarget == null)
return Response.Error(
"'target' parameter required for get_component."
);
string componentName = @params["componentName"]?.ToString();
if (string.IsNullOrEmpty(componentName))
return Response.Error(
"'componentName' parameter required for get_component."
);
return GetSingleComponentFromTarget(getSingleCompTarget, searchMethod, componentName, includeNonPublicSerialized);
case "add_component":
return AddComponentToTarget(@params, targetToken, searchMethod);
case "remove_component":
@ -1008,6 +1020,70 @@ namespace MCPForUnity.Editor.Tools
}
}
private static object GetSingleComponentFromTarget(string target, string searchMethod, string componentName, bool includeNonPublicSerialized = true)
{
GameObject targetGo = FindObjectInternal(target, searchMethod);
if (targetGo == null)
{
return Response.Error(
$"Target GameObject ('{target}') not found using method '{searchMethod ?? "default"}'."
);
}
try
{
// Try to find the component by name
Component targetComponent = targetGo.GetComponent(componentName);
// If not found directly, try to find by type name (handle namespaces)
if (targetComponent == null)
{
Component[] allComponents = targetGo.GetComponents<Component>();
foreach (Component comp in allComponents)
{
if (comp != null)
{
string typeName = comp.GetType().Name;
string fullTypeName = comp.GetType().FullName;
if (typeName == componentName || fullTypeName == componentName)
{
targetComponent = comp;
break;
}
}
}
}
if (targetComponent == null)
{
return Response.Error(
$"Component '{componentName}' not found on GameObject '{targetGo.name}'."
);
}
var componentData = Helpers.GameObjectSerializer.GetComponentData(targetComponent, includeNonPublicSerialized);
if (componentData == null)
{
return Response.Error(
$"Failed to serialize component '{componentName}' on GameObject '{targetGo.name}'."
);
}
return Response.Success(
$"Retrieved component '{componentName}' from '{targetGo.name}'.",
componentData
);
}
catch (Exception e)
{
return Response.Error(
$"Error getting component '{componentName}' from '{targetGo.name}': {e.Message}"
);
}
}
private static object AddComponentToTarget(
JObject @params,
JToken targetToken,

View File

@ -9,11 +9,11 @@ from unity_connection import send_command_with_retry
def register_manage_gameobject_tools(mcp: FastMCP):
"""Register all GameObject management tools with the MCP server."""
@mcp.tool(name="manage_gameobject", description="Manage GameObjects. Note: for 'get_components', the `data` field contains a dictionary of component names and their serialized properties.")
@mcp.tool(name="manage_gameobject", description="Manage GameObjects. Note: for 'get_components', the `data` field contains a dictionary of component names and their serialized properties. For 'get_component', specify 'component_name' to retrieve only that component's serialized data.")
@telemetry_tool("manage_gameobject")
def manage_gameobject(
ctx: Context,
action: Annotated[Literal["create", "modify", "delete", "find", "add_component", "remove_component", "set_component_property", "get_components"], "Perform CRUD operations on GameObjects and components."],
action: Annotated[Literal["create", "modify", "delete", "find", "add_component", "remove_component", "set_component_property", "get_components", "get_component"], "Perform CRUD operations on GameObjects and components."],
target: Annotated[str,
"GameObject identifier by name or path for modify/delete/component actions"] | None = None,
search_method: Annotated[Literal["by_id", "by_name", "by_path", "by_tag", "by_layer", "by_component"],