Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
6 changes: 3 additions & 3 deletions MCPForUnity/Editor/Clients/McpClientConfiguratorBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,14 +134,14 @@ protected static bool IsBetaPackageSource(string packageSource)
return true;

// PyPI prerelease range: >=0.0.0a0 (used for prerelease package builds)
if (packageSource.Contains(">=0.0.0a0", StringComparison.OrdinalIgnoreCase))
if (packageSource.IndexOf(">=0.0.0a0", StringComparison.OrdinalIgnoreCase) >= 0)
return true;

// Git-based beta references
if (packageSource.Contains("@beta", StringComparison.OrdinalIgnoreCase))
if (packageSource.IndexOf("@beta", StringComparison.OrdinalIgnoreCase) >= 0)
return true;

if (packageSource.Contains("-beta", StringComparison.OrdinalIgnoreCase))
if (packageSource.IndexOf("-beta", StringComparison.OrdinalIgnoreCase) >= 0)
return true;

return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ protected string BuildAugmentedPath()
if (additions.Length == 0) return null;

// Only return the additions - ExecPath.TryRun will prepend to existing PATH
return string.Join(Path.PathSeparator, additions);
return string.Join(Path.PathSeparator.ToString(), additions);
}

private string[] GetPathAdditions()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ protected string BuildAugmentedPath()
if (additions.Length == 0) return null;

// Only return the additions - ExecPath.TryRun will prepend to existing PATH
return string.Join(Path.PathSeparator, additions);
return string.Join(Path.PathSeparator.ToString(), additions);
}

private string[] GetPathAdditions()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ protected string BuildAugmentedPath()
if (additions.Length == 0) return null;

// Only return the additions - ExecPath.TryRun will prepend to existing PATH
return string.Join(Path.PathSeparator, additions);
return string.Join(Path.PathSeparator.ToString(), additions);
}

private string[] GetPathAdditions()
Expand Down
36 changes: 18 additions & 18 deletions MCPForUnity/Editor/External/Tommy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,7 @@ internal void WriteTo(TextWriter tw, string name, bool writeSectionName)
if (collapsedItems.Count == 0)
return;

var hasRealValues = !collapsedItems.All(n => n.Value is TomlTable { IsInline: false } or TomlArray { IsTableArray: true });
var hasRealValues = !collapsedItems.All(n => n.Value is TomlTable { IsInline: false } || n.Value is TomlArray { IsTableArray: true });

Comment?.AsComment(tw);

Expand All @@ -539,7 +539,7 @@ internal void WriteTo(TextWriter tw, string name, bool writeSectionName)
foreach (var collapsedItem in collapsedItems)
{
var key = collapsedItem.Key;
if (collapsedItem.Value is TomlArray { IsTableArray: true } or TomlTable { IsInline: false })
if (collapsedItem.Value is TomlArray { IsTableArray: true } || collapsedItem.Value is TomlTable { IsInline: false })
{
if (!first) tw.WriteLine();
first = false;
Expand Down Expand Up @@ -819,7 +819,7 @@ public TomlTable Parse()
if (TomlSyntax.IsWhiteSpace(c) || c == TomlSyntax.NEWLINE_CARRIAGE_RETURN_CHARACTER)
goto consume_character;

if (c is TomlSyntax.COMMENT_SYMBOL or TomlSyntax.NEWLINE_CHARACTER)
if (c == TomlSyntax.COMMENT_SYMBOL || c == TomlSyntax.NEWLINE_CHARACTER)
{
currentState = ParseState.None;
AdvanceLine();
Expand Down Expand Up @@ -1838,13 +1838,13 @@ internal static class TomlSyntax
public const string POS_INF_VALUE = "+inf";
public const string NEG_INF_VALUE = "-inf";

public static bool IsBoolean(string s) => s is TRUE_VALUE or FALSE_VALUE;
public static bool IsBoolean(string s) => s == TRUE_VALUE || s == FALSE_VALUE;

public static bool IsPosInf(string s) => s is INF_VALUE or POS_INF_VALUE;
public static bool IsPosInf(string s) => s == INF_VALUE || s == POS_INF_VALUE;

public static bool IsNegInf(string s) => s == NEG_INF_VALUE;

public static bool IsNaN(string s) => s is NAN_VALUE or POS_NAN_VALUE or NEG_NAN_VALUE;
public static bool IsNaN(string s) => s == NAN_VALUE || s == POS_NAN_VALUE || s == NEG_NAN_VALUE;

public static bool IsInteger(string s) => IntegerPattern.IsMatch(s);

Expand All @@ -1863,25 +1863,25 @@ public static bool IsIntegerWithBase(string s, out int numberBase)
* A pattern to verify the integer value according to the TOML specification.
*/
public static readonly Regex IntegerPattern =
new(@"^(\+|-)?(?!_)(0|(?!0)(_?\d)*)$", RegexOptions.Compiled);
new Regex(@"^(\+|-)?(?!_)(0|(?!0)(_?\d)*)$", RegexOptions.Compiled);

/**
* A pattern to verify a special 0x, 0o and 0b forms of an integer according to the TOML specification.
*/
public static readonly Regex BasedIntegerPattern =
new(@"^0(?<base>x|b|o)(?!_)(_?[0-9A-F])*$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
new Regex(@"^0(?<base>x|b|o)(?!_)(_?[0-9A-F])*$", RegexOptions.Compiled | RegexOptions.IgnoreCase);

/**
* A pattern to verify the float value according to the TOML specification.
*/
public static readonly Regex FloatPattern =
new(@"^(\+|-)?(?!_)(0|(?!0)(_?\d)+)(((e(\+|-)?(?!_)(_?\d)+)?)|(\.(?!_)(_?\d)+(e(\+|-)?(?!_)(_?\d)+)?))$",
new Regex(@"^(\+|-)?(?!_)(0|(?!0)(_?\d)+)(((e(\+|-)?(?!_)(_?\d)+)?)|(\.(?!_)(_?\d)+(e(\+|-)?(?!_)(_?\d)+)?))$",
RegexOptions.Compiled | RegexOptions.IgnoreCase);

/**
* A helper dictionary to map TOML base codes into the radii.
*/
public static readonly Dictionary<string, int> IntegerBases = new()
public static readonly Dictionary<string, int> IntegerBases = new Dictionary<string, int>()
{
["x"] = 16,
["o"] = 8,
Expand All @@ -1891,7 +1891,7 @@ public static bool IsIntegerWithBase(string s, out int numberBase)
/**
* A helper dictionary to map non-decimal bases to their TOML identifiers
*/
public static readonly Dictionary<int, string> BaseIdentifiers = new()
public static readonly Dictionary<int, string> BaseIdentifiers = new Dictionary<int, string>()
{
[2] = "b",
[8] = "o",
Expand Down Expand Up @@ -1962,29 +1962,29 @@ public static bool IsIntegerWithBase(string s, out int numberBase)

public static readonly char[] NewLineCharacters = { NEWLINE_CHARACTER, NEWLINE_CARRIAGE_RETURN_CHARACTER };

public static bool IsQuoted(char c) => c is BASIC_STRING_SYMBOL or LITERAL_STRING_SYMBOL;
public static bool IsQuoted(char c) => c == BASIC_STRING_SYMBOL || c == LITERAL_STRING_SYMBOL;

public static bool IsWhiteSpace(char c) => c is ' ' or '\t';
public static bool IsWhiteSpace(char c) => c == ' ' || c == '\t';

public static bool IsNewLine(char c) => c is NEWLINE_CHARACTER or NEWLINE_CARRIAGE_RETURN_CHARACTER;
public static bool IsNewLine(char c) => c == NEWLINE_CHARACTER || c == NEWLINE_CARRIAGE_RETURN_CHARACTER;

public static bool IsLineBreak(char c) => c == NEWLINE_CHARACTER;

public static bool IsEmptySpace(char c) => IsWhiteSpace(c) || IsNewLine(c);

public static bool IsBareKey(char c) =>
c is >= 'A' and <= 'Z' or >= 'a' and <= 'z' or >= '0' and <= '9' or '_' or '-';
(c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_' || c == '-';

public static bool MustBeEscaped(char c, bool allowNewLines = false)
{
var result = c is (>= '\u0000' and <= '\u0008') or '\u000b' or '\u000c' or (>= '\u000e' and <= '\u001f') or '\u007f';
var result = (c >= '\u0000' && c <= '\u0008') || c == '\u000b' || c == '\u000c' || (c >= '\u000e' && c <= '\u001f') || c == '\u007f';
if (!allowNewLines)
result |= c is >= '\u000a' and <= '\u000e';
result |= c >= '\u000a' && c <= '\u000e';
return result;
}

public static bool IsValueSeparator(char c) =>
c is ITEM_SEPARATOR or ARRAY_END_SYMBOL or INLINE_TABLE_END_SYMBOL;
c == ITEM_SEPARATOR || c == ARRAY_END_SYMBOL || c == INLINE_TABLE_END_SYMBOL;

#endregion
}
Expand Down
12 changes: 6 additions & 6 deletions MCPForUnity/Editor/Helpers/AssetPathUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ internal static string ResolveLocalServerPath(string path)
}

// If it looks like a PyPI package reference (no path separators), skip
if (!path.Contains('/') && !path.Contains('\\') && !path.StartsWith("file:", StringComparison.OrdinalIgnoreCase))
if (!path.Contains("/") && !path.Contains("\\") && !path.StartsWith("file:", StringComparison.OrdinalIgnoreCase))
{
return path;
}
Expand Down Expand Up @@ -658,11 +658,11 @@ private static bool IsSemVerPreRelease(string version)

// Common semver prerelease indicators:
// e.g., "9.3.0-beta.1", "9.3.0-alpha", "9.3.0-rc.2", "9.3.0-preview"
return version.Contains("-beta", StringComparison.OrdinalIgnoreCase) ||
version.Contains("-alpha", StringComparison.OrdinalIgnoreCase) ||
version.Contains("-rc", StringComparison.OrdinalIgnoreCase) ||
version.Contains("-preview", StringComparison.OrdinalIgnoreCase) ||
version.Contains("-pre", StringComparison.OrdinalIgnoreCase);
return version.IndexOf("-beta", StringComparison.OrdinalIgnoreCase) >= 0 ||
version.IndexOf("-alpha", StringComparison.OrdinalIgnoreCase) >= 0 ||
version.IndexOf("-rc", StringComparison.OrdinalIgnoreCase) >= 0 ||
version.IndexOf("-preview", StringComparison.OrdinalIgnoreCase) >= 0 ||
version.IndexOf("-pre", StringComparison.OrdinalIgnoreCase) >= 0;
}
}
}
2 changes: 1 addition & 1 deletion MCPForUnity/Editor/Helpers/CodexConfigHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ private static void EnsureRmcpClientFeature(TomlTable root)
{
if (root == null) return;

if (!root.TryGetNode("features", out var featuresNode) || featuresNode is not TomlTable features)
if (!root.TryGetNode("features", out var featuresNode) || !(featuresNode is TomlTable features))
{
features = new TomlTable();
root["features"] = features;
Expand Down
4 changes: 4 additions & 0 deletions MCPForUnity/Editor/Helpers/GameObjectLookup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
using System.Linq;
using Newtonsoft.Json.Linq;
using UnityEditor;
#if UNITY_2021_2_OR_NEWER
using UnityEditor.SceneManagement;
#else
using UnityEditor.Experimental.SceneManagement;
#endif
using UnityEngine;
using UnityEngine.SceneManagement;
using MCPForUnity.Runtime.Helpers;
Expand Down
2 changes: 1 addition & 1 deletion MCPForUnity/Editor/Helpers/HttpEndpointUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ private static string NormalizeBaseUrl(string value, string defaultUrl, bool rem
// Strip trailing "/mcp" (case-insensitive) if provided.
if (trimmed.EndsWith("/mcp", StringComparison.OrdinalIgnoreCase))
{
trimmed = trimmed[..^4];
trimmed = trimmed.Substring(0, trimmed.Length - 4);
}

// For local scope, force 127.0.0.1 over "localhost". Windows getaddrinfo returns ::1
Expand Down
2 changes: 1 addition & 1 deletion MCPForUnity/Editor/Helpers/McpConfigurationHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public static string WriteMcpConfiguration(string configPath, McpClient mcpClien
}
catch { }

JsonSerializerSettings jsonSettings = new() { Formatting = Formatting.Indented };
JsonSerializerSettings jsonSettings = new JsonSerializerSettings() { Formatting = Formatting.Indented };

// Read existing config if it exists
string existingJson = "{}";
Expand Down
5 changes: 3 additions & 2 deletions MCPForUnity/Editor/Helpers/McpLogRecord.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Linq;
using System.IO;
using MCPForUnity.Editor.Constants;
using Newtonsoft.Json;
Expand All @@ -15,7 +16,7 @@ internal static class McpLogRecord
private static readonly string ErrorLogPath = Path.Combine(LogDir, "mcpError.log");
private const long MaxLogSizeBytes = 1024 * 1024; // 1 MB
private static bool _sessionStarted;
private static readonly object _logLock = new();
private static readonly object _logLock = new object();
private static volatile bool _isEnabledCached;

[InitializeOnLoadMethod]
Expand Down Expand Up @@ -106,7 +107,7 @@ private static void RotateIfNeeded(string path)

var lines = File.ReadAllLines(path);
var half = lines.Length / 2;
File.WriteAllLines(path, lines[half..]);
File.WriteAllLines(path, new ArraySegment<string>(lines, half, lines.Length - half).ToArray());
}
catch
{
Expand Down
2 changes: 1 addition & 1 deletion MCPForUnity/Editor/Helpers/PortManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ private static string ComputeProjectHash(string input)
{
sb.Append(b.ToString("x2"));
}
return sb.ToString()[..8]; // short, sufficient for filenames
return sb.ToString().Substring(0, 8); // short, sufficient for filenames
}
catch
{
Expand Down
70 changes: 70 additions & 0 deletions MCPForUnity/Editor/Helpers/ProcessArgumentListCompat.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using System.Diagnostics;

namespace MCPForUnity.Editor.Helpers
{
/// <summary>
/// Unity 2020.3 compatibility shim: ProcessStartInfo.ArgumentList was introduced in
/// .NET Core 2.1 / netstandard2.1. On Unity 2020.3 (netstandard2.0) we emulate it
/// with ProcessStartInfo.Arguments, quoting each argument.
/// </summary>
public static class ProcessArgumentListCompat
{
/// <summary>Append one argument (quoted if it contains whitespace) — replaces ArgumentList.Add.</summary>
public static ProcessStartInfo AddArg(this ProcessStartInfo psi, string arg)
{
if (string.IsNullOrEmpty(psi.Arguments))
{
psi.Arguments = Quote(arg);
}
else
{
psi.Arguments += " " + Quote(arg);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
return psi;
}

private static string Quote(string arg)
{
if (string.IsNullOrEmpty(arg))
{
return "\"\"";
}

// Only quote when necessary; otherwise pass through verbatim so
// backslashes in paths (e.g. C:\Program Files\...) are preserved.
if (arg.IndexOfAny(new[] { ' ', '\t', '"' }) < 0)
{
return arg;
}

// Standard Windows command-line quoting (the algorithm used by
// .NET's ArgumentList / CommandLineToArgvW): wrap in quotes; for every
// run of backslashes, double them only when immediately followed by a
// quote or at the very end of the argument (before the closing quote).
var sb = new System.Text.StringBuilder();
sb.Append('"');
int backslashes = 0;
foreach (char ch in arg)
{
if (ch == '\\')
{
backslashes++;
continue;
}
if (ch == '"')
{
sb.Append('\\', backslashes * 2 + 1);
sb.Append('"');
backslashes = 0;
continue;
}
sb.Append('\\', backslashes);
backslashes = 0;
sb.Append(ch);
}
sb.Append('\\', backslashes * 2);
sb.Append('"');
return sb.ToString();
}
}
}
11 changes: 11 additions & 0 deletions MCPForUnity/Editor/Helpers/ProcessArgumentListCompat.cs.meta

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

2 changes: 1 addition & 1 deletion MCPForUnity/Editor/Helpers/ProjectIdentityUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ private static string ComputeProjectName(string dataPath)
projectPath = projectPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
if (projectPath.EndsWith("Assets", StringComparison.OrdinalIgnoreCase))
{
projectPath = projectPath[..^6].TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
projectPath = projectPath.Substring(0, projectPath.Length - 6).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
}

string name = Path.GetFileName(projectPath);
Expand Down
14 changes: 8 additions & 6 deletions MCPForUnity/Editor/Helpers/UnityTypeResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ namespace MCPForUnity.Editor.Helpers
/// </summary>
public static class UnityTypeResolver
{
private static readonly Dictionary<string, Type> CacheByFqn = new(StringComparer.Ordinal);
private static readonly Dictionary<string, Type> CacheByName = new(StringComparer.Ordinal);
private static readonly Dictionary<string, Type> CacheByFqn = new Dictionary<string, Type>(StringComparer.Ordinal);
private static readonly Dictionary<string, Type> CacheByName = new Dictionary<string, Type>(StringComparer.Ordinal);

/// <summary>
/// Resolves a type by name, with optional base type constraint.
Expand Down Expand Up @@ -150,7 +150,7 @@ private static void Cache(Type t)

private static List<Type> FindCandidates(string query, Type requiredBaseType)
{
bool isShort = !query.Contains('.');
bool isShort = !query.Contains(".");
var loaded = UnityAssembliesCompat.GetLoadedAssemblies();

#if UNITY_EDITOR
Expand All @@ -166,9 +166,11 @@ private static List<Type> FindCandidates(string query, Type requiredBaseType)
var editorAsms = Array.Empty<System.Reflection.Assembly>();
#endif

Func<Type, bool> match = isShort
? (t => t.Name.Equals(query, StringComparison.Ordinal))
: (t => t.FullName?.Equals(query, StringComparison.Ordinal) ?? false);
Func<Type, bool> match;
if (isShort)
match = t => t.Name.Equals(query, StringComparison.Ordinal);
else
match = t => t.FullName?.Equals(query, StringComparison.Ordinal) ?? false;

var fromPlayer = playerAsms.SelectMany(SafeGetTypes)
.Where(t => PassesConstraint(t, requiredBaseType))
Expand Down
2 changes: 1 addition & 1 deletion MCPForUnity/Editor/Helpers/VectorParsing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,7 @@ public static bool ValidateAnimationCurveFormat(JToken valueToken, out string me
for (int i = 0; i < keysArray.Count; i++)
{
var keyToken = keysArray[i];
if (keyToken is not JObject keyObj)
if (!(keyToken is JObject keyObj))
{
message = $"Keyframe at index {i} must be an object with 'time' and 'value'.";
return false;
Expand Down
Loading