Skip to content

Creating Custom Tools

You can extend the MCP Server with your own tools by adding a simple attribute to any C# method. No Python changes, no server restart, no tool registration — just recompile in Unity and the AI agent sees your new tool.

using realvirtual.MCP;
public static class MyTools
{
[McpTool("Get current time")]
public static string GetTime()
{
return $"{{\"time\":\"{System.DateTime.Now}\"}}";
}
[McpTool("Add two numbers")]
public static string Add(
[McpParam("First number")] float a,
[McpParam("Second number")] float b)
{
return $"{{\"result\":{a + b}}}";
}
}

That’s it. After recompilation, get_time and add are available to any connected AI agent.

Add [McpTool("description")] to any public static method that returns a string. The description tells the AI agent what the tool does.

[McpTool("Spawn an enemy at position")]
public static string SpawnEnemy(
[McpParam("Prefab name")] string prefab,
[McpParam("X position")] float x,
[McpParam("Z position")] float z)
{
// Your Unity code here - runs on main thread
return ToolHelpers.Ok("Enemy spawned");
}

Add [McpParam("description")] to parameters to give the AI agent context about what values to provide. Optional parameters need default values.

[McpTool("Set weather")]
public static string SetWeather(
[McpParam("Weather type: sunny, rainy, cloudy")] string weather,
[McpParam("Wind speed in m/s")] float windSpeed = 0f)
{
// windSpeed is optional, defaults to 0
return ToolHelpers.Ok($"Weather set to {weather}");
}
  • Method must be public static and return string (JSON)
  • Tool names auto-convert from PascalCase to snake_case (SpawnEnemy → spawn_enemy)
  • Methods can be in any class, in any assembly — they are found via reflection
  • All tool methods run on Unity’s main thread
  • Return JSON strings — use ToolHelpers.Ok() and ToolHelpers.Error() for standard responses

The ToolHelpers class provides common patterns:

// Find a GameObject by hierarchy path
var go = ToolHelpers.FindGameObject("Robot/Arm/Gripper");
// Return success
return ToolHelpers.Ok("Operation completed");
// Return success with data
return ToolHelpers.Ok(new { position = transform.position });
// Return error
return ToolHelpers.Error("GameObject not found");
using realvirtual.MCP;
using UnityEngine;
public static class FactoryTools
{
[McpTool("Get temperature from all sensors in the factory")]
public static string GetTemperatures()
{
var sensors = Object.FindObjectsByType<TemperatureSensor>(
FindObjectsSortMode.None);
var results = sensors.Select(s => new {
name = s.gameObject.name,
temperature = s.CurrentTemperature,
unit = "celsius"
}).ToArray();
return JsonUtility.ToJson(new { sensors = results });
}
}

After recompiling, the AI agent can call get_temperatures and receive structured data about all temperature sensors in the scene.