diff --git a/MCPForUnity/Editor/Clients/Configurators/PiConfigurator.cs b/MCPForUnity/Editor/Clients/Configurators/PiConfigurator.cs
new file mode 100644
index 000000000..ade5a703b
--- /dev/null
+++ b/MCPForUnity/Editor/Clients/Configurators/PiConfigurator.cs
@@ -0,0 +1,98 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using MCPForUnity.Editor.Models;
+
+namespace MCPForUnity.Editor.Clients.Configurators
+{
+ ///
+ /// Pi (pi.dev) configurator.
+ ///
+ /// Two things make Pi different from every other JSON client in this folder, and both are
+ /// load-bearing rather than cosmetic:
+ ///
+ /// 1. Pi has no built-in MCP client. As of pi 0.84.x there is no mcp subcommand,
+ /// no --mcp-config equivalent, and no mcp.json reader anywhere in the
+ /// distributed package; its own README states "No MCP. Build CLI tools with READMEs, or
+ /// build an extension that adds MCP support." Reaching this server from Pi therefore
+ /// requires an MCP extension, and the unityMCP entry written below is what that
+ /// extension reads. names the extension explicitly,
+ /// because on Pi a config file alone is a silent no-op — the exact "configured, enabled, and
+ /// silently providing nothing" shape this window exists to prevent.
+ ///
+ /// 2. The file is shared, so presence cannot be inferred from it. Pi MCP extensions read
+ /// the tool-agnostic ~/.config/mcp/mcp.json, not a Pi-owned path. That makes the
+ /// inherited IsInstalled ("does the config path's parent directory exist") wrong in
+ /// both directions — see .
+ ///
+ public class PiConfigurator : JsonFileMcpConfigurator
+ {
+ public PiConfigurator() : base(new McpClient
+ {
+ name = "Pi",
+ windowsConfigPath = GetSharedMcpConfigPath(),
+ macConfigPath = GetSharedMcpConfigPath(),
+ linuxConfigPath = GetSharedMcpConfigPath()
+ })
+ { }
+
+ ///
+ /// Pi-exclusive presence check, deliberately NOT the inherited
+ /// ParentDirectoryExists(GetConfigPath()).
+ ///
+ ///
+ /// The config path here is a SHARED, tool-agnostic file. Its parent directory therefore says
+ /// nothing about whether Pi exists: a Cursor or Claude Code user has a
+ /// ~/.config/mcp tree without ever installing Pi, and a Pi user who has not yet
+ /// configured any MCP server has no ~/.config/mcp at all. Keying detection on that
+ /// path would make "Configure All Detected Clients" offer Pi on machines that do not have
+ /// it while skipping the exact machines this configurator exists to fix.
+ ///
+ ///
+ ///
+ /// Pi's own agent directory is the correct marker: pi creates it on first run for settings,
+ /// sessions and auth, nothing else writes there, and PI_CODING_AGENT_DIR relocates
+ /// it — so an explicitly relocated install is detected too rather than hardcoding
+ /// ~/.pi.
+ ///
+ ///
+ public override bool IsInstalled
+ {
+ get
+ {
+ string agentDir = GetPiAgentDirectory();
+ return !string.IsNullOrEmpty(agentDir) && Directory.Exists(agentDir);
+ }
+ }
+
+ public override IList GetInstallationSteps() => new List
+ {
+ "Install an MCP extension for Pi — Pi ships no MCP client of its own:\npi install npm:pi-mcp-adapter",
+ "Restart Pi so the extension loads (extensions are read at startup)",
+ "Paste the configuration JSON into the file at the path above, or use Configure",
+ "Start Pi and ask it to search MCP — e.g. \"search MCP for manage_gameobject\""
+ };
+
+ /// The tool-agnostic shared MCP config Pi MCP extensions read, in the user's home.
+ private static string GetSharedMcpConfigPath()
+ {
+ string home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
+ return Path.Combine(home, ".config", "mcp", "mcp.json");
+ }
+
+ ///
+ /// Pi's agent directory: $PI_CODING_AGENT_DIR when set (Pi's own documented
+ /// relocation override), else ~/.pi/agent. Null when the home directory cannot be
+ /// resolved, which callers must treat as "not installed" rather than as a match.
+ ///
+ private static string GetPiAgentDirectory()
+ {
+ string overrideDir = Environment.GetEnvironmentVariable("PI_CODING_AGENT_DIR");
+ if (!string.IsNullOrWhiteSpace(overrideDir))
+ return overrideDir.Trim();
+
+ string home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
+ return string.IsNullOrEmpty(home) ? null : Path.Combine(home, ".pi", "agent");
+ }
+ }
+}
diff --git a/MCPForUnity/Editor/Clients/Configurators/PiConfigurator.cs.meta b/MCPForUnity/Editor/Clients/Configurators/PiConfigurator.cs.meta
new file mode 100644
index 000000000..2e4b06e63
--- /dev/null
+++ b/MCPForUnity/Editor/Clients/Configurators/PiConfigurator.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 068ab66d5e4b41f98382460c25b4f3a8
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/TestProjects/UnityMCPTests/Assets/Tests/EditMode/Clients/IsInstalledTests.cs b/TestProjects/UnityMCPTests/Assets/Tests/EditMode/Clients/IsInstalledTests.cs
index e7d4467cb..ee425619e 100644
--- a/TestProjects/UnityMCPTests/Assets/Tests/EditMode/Clients/IsInstalledTests.cs
+++ b/TestProjects/UnityMCPTests/Assets/Tests/EditMode/Clients/IsInstalledTests.cs
@@ -41,5 +41,52 @@ public void JsonClient_Installed_WhenParentDirExists()
bool expected = parent != null && Directory.Exists(parent);
Assert.AreEqual(expected, claude.IsInstalled);
}
+
+ ///
+ /// Pi's presence check must key on Pi's OWN agent directory, honouring
+ /// PI_CODING_AGENT_DIR. The file it writes is the tool-agnostic shared
+ /// ~/.config/mcp/mcp.json, so the inherited "parent directory of the config path
+ /// exists" rule would answer a different question entirely.
+ ///
+ [Test]
+ public void PiConfigurator_PresenceIsAgentDirBased()
+ {
+ var pi = new PiConfigurator();
+ Assert.AreEqual(Directory.Exists(PiAgentDirectory()), pi.IsInstalled,
+ "Pi detection must follow Pi's agent directory, honouring PI_CODING_AGENT_DIR");
+ }
+
+ ///
+ /// The specific over-report this configurator guards against: a shared MCP config tree with
+ /// no Pi install beside it must NOT read as "Pi detected". Cursor and Claude Code users have
+ /// ~/.config/mcp without ever installing Pi, so keying on it would offer Pi in
+ /// "Configure All Detected Clients" on machines that do not have it. Skipped (Pass) when Pi
+ /// is genuinely installed here or when no shared tree exists -- neither host can distinguish
+ /// the two rules, so asserting there would prove nothing.
+ ///
+ [Test]
+ public void PiConfigurator_SharedMcpConfigTreeAlone_IsNotInstalled()
+ {
+ var pi = new PiConfigurator();
+ string sharedParent = Path.GetDirectoryName(pi.GetConfigPath());
+
+ if (sharedParent == null || !Directory.Exists(sharedParent))
+ Assert.Pass("no shared MCP config tree on this machine -- nothing to distinguish");
+ if (Directory.Exists(PiAgentDirectory()))
+ Assert.Pass("Pi is installed on this machine -- the over-report case needs a host without it");
+
+ Assert.IsFalse(pi.IsInstalled,
+ "the shared MCP config tree is not evidence of a Pi install; detection must key on Pi's agent dir");
+ }
+
+ private static string PiAgentDirectory()
+ {
+ string overrideDir = System.Environment.GetEnvironmentVariable("PI_CODING_AGENT_DIR");
+ if (!string.IsNullOrWhiteSpace(overrideDir))
+ return overrideDir.Trim();
+
+ string home = System.Environment.GetFolderPath(System.Environment.SpecialFolder.UserProfile);
+ return Path.Combine(home, ".pi", "agent");
+ }
}
}
diff --git a/website/docs/getting-started/clients.md b/website/docs/getting-started/clients.md
index 0be1ff516..245d17a25 100644
--- a/website/docs/getting-started/clients.md
+++ b/website/docs/getting-started/clients.md
@@ -26,13 +26,14 @@ 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. |
+| **Pi** | stdio / HTTP | yes | yes | yes | Needs an MCP extension (Pi ships no MCP client of its own): `pi install npm:pi-mcp-adapter`. Writes the shared `~/.config/mcp/mcp.json`. |
## How to pick
- **You want it to just work**: Claude Desktop. Stdio means no port conflicts and no firewall prompts.
- **You're building a multi-agent or remote workflow**: anything HTTP. Multiple clients can share one Python server; see [Multi-Instance Routing](/guides/multi-instance).
- **You're already in your IDE**: Cursor, VS Code Copilot, or Cline — keeps you in flow.
-- **You want a terminal**: Claude Code, Copilot CLI, Codex, Gemini CLI, or Qwen Code.
+- **You want a terminal**: Claude Code, Copilot CLI, Codex, Gemini CLI, Qwen Code, or Pi.
## Manual configuration
@@ -45,6 +46,8 @@ A few clients need an MCP toggle flipped on after the configurator writes their
- **Cursor** → Settings → MCP → enable the `unityMCP` server
- **Antigravity** → Settings → MCP servers → enable
- **OpenClaw** → enable the `openclaw-mcp-bridge` plugin
+- **Pi** → install an MCP extension first (`pi install npm:pi-mcp-adapter`) and restart Pi; Pi has no
+ built-in MCP client, so the config file alone does nothing
Everything else just connects on next launch.