Skip to content

Commit 549ac1e

Browse files
authored
Add Codex to autoconfig options (#288)
* feat: add Codex CLI client support with config.toml handling * feat: add config helpers for managing Codex and MCP server configurations * feat: add TOML array parsing support for multi-line and trailing comma formats * fix: handle TOML inline comments in section headers during parsing * fix: strip TOML comments before processing section headers * fix: improve JSON parsing to handle escaped single quotes in config strings * Use Tommy for TOML parsing It's a single file and OSS, easy to integrate into Unity * fix: patched Tommy’s literal-string handling so doubled single quotes inside literal strings are treated as embedded apostrophes instead of prematurely ending the value * Don't overwrite MCP configs while testing Seeing random JSON in my codex config was pretty annoying * PR Feedback * Keep Tommy compatible with Unity 2021 * Re-include Tommy's license Probably a good habit to keep all 3rd party licenses and copyrights, even if they're also MIT licenses
1 parent da91f25 commit 549ac1e

File tree

15 files changed

+2938
-230
lines changed

15 files changed

+2938
-230
lines changed

TestProjects/UnityMCPTests/Assets/Tests/EditMode/Helpers.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
using NUnit.Framework;
2+
using MCPForUnity.Editor.Helpers;
3+
4+
namespace MCPForUnityTests.Editor.Helpers
5+
{
6+
public class CodexConfigHelperTests
7+
{
8+
[Test]
9+
public void TryParseCodexServer_SingleLineArgs_ParsesSuccessfully()
10+
{
11+
string toml = string.Join("\n", new[]
12+
{
13+
"[mcp_servers.unityMCP]",
14+
"command = \"uv\"",
15+
"args = [\"run\", \"--directory\", \"/abs/path\", \"server.py\"]"
16+
});
17+
18+
bool result = CodexConfigHelper.TryParseCodexServer(toml, out string command, out string[] args);
19+
20+
Assert.IsTrue(result, "Parser should detect server definition");
21+
Assert.AreEqual("uv", command);
22+
CollectionAssert.AreEqual(new[] { "run", "--directory", "/abs/path", "server.py" }, args);
23+
}
24+
25+
[Test]
26+
public void TryParseCodexServer_MultiLineArgsWithTrailingComma_ParsesSuccessfully()
27+
{
28+
string toml = string.Join("\n", new[]
29+
{
30+
"[mcp_servers.unityMCP]",
31+
"command = \"uv\"",
32+
"args = [",
33+
" \"run\",",
34+
" \"--directory\",",
35+
" \"/abs/path\",",
36+
" \"server.py\",",
37+
"]"
38+
});
39+
40+
bool result = CodexConfigHelper.TryParseCodexServer(toml, out string command, out string[] args);
41+
42+
Assert.IsTrue(result, "Parser should handle multi-line arrays with trailing comma");
43+
Assert.AreEqual("uv", command);
44+
CollectionAssert.AreEqual(new[] { "run", "--directory", "/abs/path", "server.py" }, args);
45+
}
46+
47+
[Test]
48+
public void TryParseCodexServer_MultiLineArgsWithComments_IgnoresComments()
49+
{
50+
string toml = string.Join("\n", new[]
51+
{
52+
"[mcp_servers.unityMCP]",
53+
"command = \"uv\"",
54+
"args = [",
55+
" \"run\", # launch command",
56+
" \"--directory\",",
57+
" \"/abs/path\",",
58+
" \"server.py\"",
59+
"]"
60+
});
61+
62+
bool result = CodexConfigHelper.TryParseCodexServer(toml, out string command, out string[] args);
63+
64+
Assert.IsTrue(result, "Parser should tolerate comments within the array block");
65+
Assert.AreEqual("uv", command);
66+
CollectionAssert.AreEqual(new[] { "run", "--directory", "/abs/path", "server.py" }, args);
67+
}
68+
69+
[Test]
70+
public void TryParseCodexServer_HeaderWithComment_StillDetected()
71+
{
72+
string toml = string.Join("\n", new[]
73+
{
74+
"[mcp_servers.unityMCP] # annotated header",
75+
"command = \"uv\"",
76+
"args = [\"run\", \"--directory\", \"/abs/path\", \"server.py\"]"
77+
});
78+
79+
bool result = CodexConfigHelper.TryParseCodexServer(toml, out string command, out string[] args);
80+
81+
Assert.IsTrue(result, "Parser should recognize section headers even with inline comments");
82+
Assert.AreEqual("uv", command);
83+
CollectionAssert.AreEqual(new[] { "run", "--directory", "/abs/path", "server.py" }, args);
84+
}
85+
86+
[Test]
87+
public void TryParseCodexServer_SingleQuotedArgsWithApostrophes_ParsesSuccessfully()
88+
{
89+
string toml = string.Join("\n", new[]
90+
{
91+
"[mcp_servers.unityMCP]",
92+
"command = 'uv'",
93+
"args = ['run', '--directory', '/Users/O''Connor/codex', 'server.py']"
94+
});
95+
96+
bool result = CodexConfigHelper.TryParseCodexServer(toml, out string command, out string[] args);
97+
98+
Assert.IsTrue(result, "Parser should accept single-quoted arrays with escaped apostrophes");
99+
Assert.AreEqual("uv", command);
100+
CollectionAssert.AreEqual(new[] { "run", "--directory", "/Users/O'Connor/codex", "server.py" }, args);
101+
}
102+
}
103+
}

TestProjects/UnityMCPTests/Assets/Tests/EditMode/Helpers/CodexConfigHelperTests.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

TestProjects/UnityMCPTests/Assets/Tests/EditMode/Windows/WriteToConfigTests.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ public void SetUp()
4646
EditorPrefs.SetString("MCPForUnity.ServerSrc", _serverSrcDir);
4747
// Ensure no lock is enabled
4848
EditorPrefs.SetBool("MCPForUnity.LockCursorConfig", false);
49+
// Disable auto-registration to avoid hitting user configs during tests
50+
EditorPrefs.SetBool("MCPForUnity.AutoRegisterEnabled", false);
4951
}
5052

5153
[TearDown]
@@ -54,6 +56,7 @@ public void TearDown()
5456
// Clean up editor preferences set during SetUp
5557
EditorPrefs.DeleteKey("MCPForUnity.ServerSrc");
5658
EditorPrefs.DeleteKey("MCPForUnity.LockCursorConfig");
59+
EditorPrefs.DeleteKey("MCPForUnity.AutoRegisterEnabled");
5760

5861
// Remove temp files
5962
try { if (Directory.Exists(_tempRoot)) Directory.Delete(_tempRoot, true); } catch { }

UnityMcpBridge/Editor/Data/McpClients.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,28 @@ public class McpClients
159159
mcpType = McpTypes.Kiro,
160160
configStatus = "Not Configured",
161161
},
162+
// 4) Codex CLI
163+
new()
164+
{
165+
name = "Codex CLI",
166+
windowsConfigPath = Path.Combine(
167+
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
168+
".codex",
169+
"config.toml"
170+
),
171+
macConfigPath = Path.Combine(
172+
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
173+
".codex",
174+
"config.toml"
175+
),
176+
linuxConfigPath = Path.Combine(
177+
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
178+
".codex",
179+
"config.toml"
180+
),
181+
mcpType = McpTypes.Codex,
182+
configStatus = "Not Configured",
183+
},
162184
};
163185

164186
// Initialize status enums after construction
@@ -174,4 +196,3 @@ public McpClients()
174196
}
175197
}
176198
}
177-

UnityMcpBridge/Editor/External.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)