Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions MCPForUnity/Editor/Clients/Configurators/DroidConfigurator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.IO;
using MCPForUnity.Editor.Models;

namespace MCPForUnity.Editor.Clients.Configurators
{
/// <summary>
/// Factory Droid configurator. Droid stores MCP server config in
/// ~/.factory/mcp.json using the standard `mcpServers` container, so it
/// reuses the shared JSON-file configurator pipeline.
/// </summary>
public class DroidConfigurator : JsonFileMcpConfigurator
{
public DroidConfigurator() : base(new McpClient
{
name = "Droid",
// ~/.factory/mcp.json on every OS (UserProfile resolves to C:\Users\<user> on Windows).
windowsConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".factory", "mcp.json"),
macConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".factory", "mcp.json"),
linuxConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".factory", "mcp.json"),
SupportsHttpTransport = true,
})
{ }

public override bool SupportsSkills => true;

public override string GetSkillInstallPath()
{
var userHome = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
return Path.Combine(userHome, ".factory", "skills", "unity-mcp-skill");
}

public override IList<string> GetInstallationSteps() => new List<string>
{
"Install Factory Droid (https://factory.ai)",
"Click Configure to add UnityMCP to ~/.factory/mcp.json\nOR open the config file at the path above",
"Paste the configuration JSON into the mcpServers object",
"Save and restart Droid"
Comment on lines +35 to +38
};
}
}
11 changes: 11 additions & 0 deletions MCPForUnity/Editor/Clients/Configurators/DroidConfigurator.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,14 @@ public void JsonClient_Installed_WhenParentDirExists()
bool expected = parent != null && Directory.Exists(parent);
Assert.AreEqual(expected, claude.IsInstalled);
}

[Test]
public void Droid_Installed_WhenFactoryDirExists()
{
var droid = new DroidConfigurator();
string parent = Path.GetDirectoryName(droid.GetConfigPath());
bool expected = parent != null && Directory.Exists(parent);
Assert.AreEqual(expected, droid.IsInstalled);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,14 @@ public void Cursor_SupportsBothTransports()
CollectionAssert.Contains(list, ConfiguredTransport.Stdio);
CollectionAssert.Contains(list, ConfiguredTransport.Http);
}

[Test]
public void Droid_SupportsBothTransports()
{
var droid = new DroidConfigurator();
var list = droid.SupportedTransports.ToList();
CollectionAssert.Contains(list, ConfiguredTransport.Stdio);
CollectionAssert.Contains(list, ConfiguredTransport.Http);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -152,5 +152,73 @@ public void BuildManualConfigJson_ForGenericHttpClient_UsesPlainHttpType()
Assert.AreEqual("http", (string)unity["type"],
"Clients without HttpTypeValue should keep the generic type:http");
}

[Test]
public void DroidConfigurator_DeclaresStandardMcpServersFormat()
{
// Droid stores MCP config in ~/.factory/mcp.json using the standard mcpServers
// container, so it must not override ServerContainerKey/HttpTypeValue/StdioTypeValue
// (those overrides are for clients with non-standard schemas like Kilo Code).
var client = new DroidConfigurator().Client;

Assert.IsTrue(string.IsNullOrEmpty(client.ServerContainerKey),
"Droid must use the default mcpServers container, not a client-specific one");
Assert.IsTrue(string.IsNullOrEmpty(client.HttpTypeValue),
"Droid must use the generic type:http for HTTP transport");
Assert.IsTrue(string.IsNullOrEmpty(client.StdioTypeValue),
"Droid must use the generic type:stdio for stdio transport");
Assert.IsFalse(client.IsVsCodeLayout,
"Droid must not use the VS Code servers/mcp.servers layout");
Assert.IsTrue(client.SupportsHttpTransport,
"Droid supports both stdio and HTTP transports");
}

[Test]
public void BuildManualConfigJson_ForDroid_UsesMcpServersContainerAndPlainHttp()
{
var client = new DroidConfigurator().Client;

var root = JObject.Parse(ConfigJsonBuilder.BuildManualConfigJson(uvPath: null, client));

Assert.IsNull(root["$schema"], "Droid must not write a $schema");
Assert.IsNull(root["mcp"], "Droid must not use a client-specific container");

var unity = (JObject)root.SelectToken("mcpServers.unityMCP");
Assert.NotNull(unity, "Expected mcpServers.unityMCP node");
Assert.AreEqual("http", (string)unity["type"],
"Droid HTTP config must use the generic type:http, not streamableHttp/remote");
Assert.IsNotNull(unity["url"], "HTTP transport should set a url");
Assert.IsNull(unity["command"], "HTTP transport should not include a command");
}

[Test]
public void DroidConfigurator_TargetsFactoryMcpJson_OnAllPlatforms()
{
var client = new DroidConfigurator().Client;
const string expectedFileName = "mcp.json";
const string expectedParentDirName = ".factory";

foreach (var path in new[] { client.windowsConfigPath, client.macConfigPath, client.linuxConfigPath })
{
Assert.AreEqual(expectedFileName, System.IO.Path.GetFileName(path),
"Droid config must target mcp.json");
Assert.AreEqual(expectedParentDirName, System.IO.Path.GetFileName(System.IO.Path.GetDirectoryName(path)),
"Droid config must live inside ~/.factory/");
}
}

[Test]
public void DroidConfigurator_SupportsSkills_AndInstallsUnderFactorySkills()
{
var droid = new DroidConfigurator();

Assert.IsTrue(droid.SupportsSkills, "Droid should support skill installation");
string skillPath = droid.GetSkillInstallPath();
Assert.IsNotNull(skillPath, "Skill install path must not be null when SupportsSkills is true");
StringAssert.Contains(".factory", skillPath,
"Droid skills should install under ~/.factory/skills/");
StringAssert.EndsWith("unity-mcp-skill", skillPath,
"Droid skill install path should end with the unity-mcp-skill subdirectory");
}
}
}
1 change: 1 addition & 0 deletions website/docs/getting-started/clients.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ MCP for Unity auto-configures every client the package detects on your machine.
| **Gemini CLI** | HTTP | yes | yes | yes | Auto-connects. |
| **OpenClaw** | HTTP / stdio | yes | yes | yes | Requires `openclaw-mcp-bridge` plugin enabled. Follows MCP for Unity's transport choice. |
| **Antigravity** | HTTP | yes | yes | varies | Requires an MCP toggle in Antigravity settings. |
| **Droid** | HTTP | yes | yes | yes | Factory's agent. Config written to `~/.factory/mcp.json`. |

## How to pick

Expand Down
2 changes: 1 addition & 1 deletion website/docs/getting-started/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Three install paths are supported. Pick one. **Git URL** is the fastest if you j

- **Unity 2021.3 LTS or newer** — [Download Unity](https://unity.com/download)
- **Python 3.10+** with [`uv`](https://docs.astral.sh/uv/getting-started/installation/) — the setup wizard guides you through both if missing
- **An MCP client** — [Claude Desktop](https://claude.ai/download), [Claude Code](https://docs.anthropic.com/en/docs/claude-code), [Cursor](https://www.cursor.com/), [VS Code Copilot](https://code.visualstudio.com/docs/copilot/overview), [GitHub Copilot CLI](https://docs.github.com/en/copilot/concepts/agents/about-copilot-cli), [Windsurf](https://windsurf.com/), [Cline](https://cline.bot/), [OpenClaw](https://openclaw.ai/), and more
- **An MCP client** — [Claude Desktop](https://claude.ai/download), [Claude Code](https://docs.anthropic.com/en/docs/claude-code), [Cursor](https://www.cursor.com/), [VS Code Copilot](https://code.visualstudio.com/docs/copilot/overview), [GitHub Copilot CLI](https://docs.github.com/en/copilot/concepts/agents/about-copilot-cli), [Windsurf](https://windsurf.com/), [Cline](https://cline.bot/), [OpenClaw](https://openclaw.ai/), [Factory Droid](https://factory.ai/), and more

## Option 1 — Git URL (fastest)

Expand Down
1 change: 1 addition & 0 deletions website/docs/guides/client-configurators.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ At a high level:
Most MCP clients use a JSON config file that defines one or more MCP servers. Examples:

- **Cursor** – `JsonFileMcpConfigurator` (global `~/.cursor/mcp.json`).
- **Droid** – `JsonFileMcpConfigurator` (global `~/.factory/mcp.json`, standard `mcpServers` layout; skills install to `~/.factory/skills/unity-mcp-skill`).
- **VSCode GitHub Copilot** – `JsonFileMcpConfigurator` with `IsVsCodeLayout = true`.
- **VSCode Insiders GitHub Copilot** – `JsonFileMcpConfigurator` with `IsVsCodeLayout = true` and Insider-specific `Code - Insiders/User/mcp.json` paths.
- **GitHub Copilot CLI** – `JsonFileMcpConfigurator` with standard HTTP transport.
Expand Down