Skip to content

Commit bdabccd

Browse files
authored
Merge pull request #38 from notargs/brush_up_get_logs
Implement GetCurrentConsoleLogs & ClearConsoleLogs
2 parents 9eb43e1 + 79836fc commit bdabccd

10 files changed

Lines changed: 155 additions & 60 deletions

File tree

README.ja.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ Node.jsで実装された、MCPクライアントとUnity間の通信を中継
4949
現在、次のMCPツールが実装されています。
5050

5151
- **RefreshAssets**: Unity Editorのアセットを更新
52-
- **GetLogHistory**: Unity Consoleのログ履歴を取得
52+
- **GetCurrentConsoleLogs**: Unity Consoleのログを取得
53+
- **ClearConsoleLogs**: Unity Consoleのログをクリア
5354

5455
## Installation
5556

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ A Unity project for functional verification and as a sample.
4949
Currently, the following MCP tools are implemented:
5050

5151
- **RefreshAssets**: Refresh Unity Editor assets
52-
- **GetLogHistory**: Get Unity Console log history
52+
- **GetCurrentConsoleLogs**: Get Unity Console log history
53+
- **ClearConsoleLogs**: Clear Unity Console logs
5354

5455
## Installation
5556

UnityNaturalMCPServer/Editor/McpServerRunner.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ internal static class McpServerRunner
1414
[InitializeOnLoadMethod]
1515
private static void Init()
1616
{
17-
LogCollector.Initialize();
1817
var cancellationTokenSource = new CancellationTokenSource();
1918
cancellationTokenSource.AddTo(Application.exitCancellationToken);
2019
_mcpServerApplication = new McpServerApplication();

UnityNaturalMCPServer/Editor/McpTools/LogCollector.cs

Lines changed: 0 additions & 36 deletions
This file was deleted.

UnityNaturalMCPServer/Editor/McpTools/LogCollector.cs.meta

Lines changed: 0 additions & 3 deletions
This file was deleted.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
namespace UnityNaturalMCP.Editor.McpTools
2+
{
3+
internal record LogEntry(string Condition, string Type);
4+
}

UnityNaturalMCPServer/Editor/McpTools/LogEntry.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using System;
2+
3+
namespace UnityNaturalMCP.Editor.McpTools
4+
{
5+
[Flags]
6+
internal enum LogMessageFlags : int
7+
{
8+
NoLogMessageFlags = 0,
9+
Error = 1 << 0,
10+
Assert = 1 << 1,
11+
Log = 1 << 2,
12+
Fatal = 1 << 4,
13+
AssetImportError = 1 << 6,
14+
AssetImportWarning = 1 << 7,
15+
ScriptingError = 1 << 8,
16+
ScriptingWarning = 1 << 9,
17+
ScriptingLog = 1 << 10,
18+
ScriptCompileError = 1 << 11,
19+
ScriptCompileWarning = 1 << 12,
20+
StickyLog = 1 << 13,
21+
MayIgnoreLineNumber = 1 << 14,
22+
ReportBug = 1 << 15,
23+
DisplayPreviousErrorInStatusBar = 1 << 16,
24+
ScriptingException = 1 << 17,
25+
DontExtractStacktrace = 1 << 18,
26+
ScriptingAssertion = 1 << 21,
27+
StacktraceIsPostprocessed = 1 << 22,
28+
IsCalledFromManaged = 1 << 23
29+
}
30+
}

UnityNaturalMCPServer/Editor/McpTools/LogMessageFlags.cs.meta

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 112 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
using System;
22
using System.Collections.Generic;
33
using System.ComponentModel;
4+
using System.Linq;
5+
using System.Reflection;
6+
using System.Text.RegularExpressions;
7+
using System.Threading.Tasks;
48
using Cysharp.Threading.Tasks;
59
using ModelContextProtocol.Server;
610
using UnityEditor;
711
using UnityEngine;
12+
using Assert = UnityEngine.Assertions.Assert;
813

914
namespace UnityNaturalMCP.Editor.McpTools
1015
{
@@ -14,30 +19,119 @@ internal sealed class McpUnityEditorTool
1419
[McpServerTool, Description("Execute AssetDatabase.Refresh")]
1520
public async UniTask RefreshAssets()
1621
{
17-
await UniTask.SwitchToMainThread();
18-
AssetDatabase.Refresh();
22+
try
23+
{
24+
await UniTask.SwitchToMainThread();
25+
AssetDatabase.Refresh();
26+
}
27+
catch (Exception e)
28+
{
29+
Debug.LogError(e);
30+
throw;
31+
}
1932
}
20-
[McpServerTool, Description("Get log history.")]
21-
public IReadOnlyList<LogEntry> GetLogHistory(
22-
[Description("Filter logs by type. Valid values: \"All\", \"Error\", \"Assert\", \"Warning\", \"Exception\"")]
23-
string logType)
33+
34+
[McpServerTool, Description("Get current console logs. Recommend calling ClearConsoleLogs beforehand.")]
35+
public async Task<IReadOnlyList<LogEntry>> GetCurrentConsoleLogs(
36+
[Description(
37+
"Filter logs by type. Valid values: \"\"(Maches all logs), \"error\", \"warning\", \"log\", \"compile-error\"(This is all you need to check for compilation errors.), \"compile-warning\"")]
38+
string logType = "",
39+
[Description("Filter by regex. If empty, all logs are returned.")]
40+
string filter = "",
41+
[Description("Log count limit. Set to 0 for no limit(Not recommended).")]
42+
int maxCount = 20,
43+
[Description("Get only first line of the log message. If false, the whole message is returned.(To save tokens, recommend calling this with true.)")]
44+
bool onlyFirstLine = true,
45+
[Description(
46+
"If true, the logs will be sorted by time in chronological order(oldest first). If false, newest first.")]
47+
bool isChronological = false)
2448
{
25-
if (logType.ToLower() == "all")
49+
try
50+
{
51+
await UniTask.SwitchToMainThread();
52+
var logTypeToLower = logType.ToLower();
53+
var logs = new List<LogEntry>();
54+
var logEntries = Type.GetType("UnityEditor.LogEntries,UnityEditor.dll");
55+
Assert.IsNotNull(logEntries);
56+
57+
var getCountMethod = logEntries.GetMethod("GetCount", BindingFlags.Public | BindingFlags.Static);
58+
var getEntryInternalMethod = logEntries.GetMethod("GetEntryInternal", BindingFlags.Public | BindingFlags.Static);
59+
60+
Assert.IsNotNull(getCountMethod);
61+
Assert.IsNotNull(getEntryInternalMethod);
62+
63+
var count = (int)getCountMethod.Invoke(null, null);
64+
65+
for (var i = 0; i < count; i++)
66+
{
67+
var logEntryType = Type.GetType("UnityEditor.LogEntry,UnityEditor.dll");
68+
Assert.IsNotNull(logEntryType);
69+
70+
var logEntry = Activator.CreateInstance(logEntryType);
71+
72+
getEntryInternalMethod.Invoke(null, new[] { i, logEntry });
73+
74+
var message = logEntry.GetType().GetField("message").GetValue(logEntry) as string ?? "";
75+
var file = logEntry.GetType().GetField("file").GetValue(logEntry) as string ?? "";
76+
var mode = (int)logEntry.GetType().GetField("mode").GetValue(logEntry);
77+
var logTypeValue = UnityInternalLogModeToLogType(mode);
78+
79+
if ((string.IsNullOrEmpty(logTypeToLower) || logTypeValue.Equals(logTypeToLower))
80+
&& (string.IsNullOrEmpty(filter) || Regex.IsMatch(message, filter)))
81+
{
82+
logs.Add(new LogEntry(onlyFirstLine ? message.Split('\n')[0] : message, logTypeValue));
83+
}
84+
}
85+
86+
if (!isChronological)
87+
{
88+
logs = ((IEnumerable<LogEntry>)logs).Reverse().ToList();
89+
}
90+
91+
if (maxCount > 0)
92+
{
93+
logs = logs.Take(maxCount).ToList();
94+
}
95+
96+
return logs;
97+
}
98+
catch (Exception e)
2699
{
27-
return LogCollector.LogHistory;
100+
Debug.LogError(e);
101+
throw;
28102
}
103+
}
104+
105+
[McpServerTool, Description("Clear console logs. It is recommended to call it before GetCurrentConsoleLogs.")]
106+
public async Task ClearConsoleLogs()
107+
{
108+
try
109+
{
110+
await UniTask.SwitchToMainThread();
111+
var logEntries = Type.GetType("UnityEditor.LogEntries,UnityEditor.dll");
112+
Assert.IsNotNull(logEntries);
113+
114+
var clearMethod = logEntries.GetMethod("Clear", BindingFlags.Public | BindingFlags.Static);
29115

30-
var logTypeEnum = logType.ToLower() switch
116+
Assert.IsNotNull(clearMethod);
117+
118+
clearMethod.Invoke(null, null);
119+
}
120+
catch (Exception e)
31121
{
32-
"error" => LogType.Error,
33-
"assert" => LogType.Assert,
34-
"warning" => LogType.Warning,
35-
"log" => LogType.Log,
36-
"exception" => LogType.Exception,
37-
_ => throw new ArgumentOutOfRangeException(nameof(logType), logType, null)
38-
};
39-
40-
return LogCollector.GetLogHistory(logTypeEnum);
122+
Debug.LogError(e);
123+
throw;
124+
}
41125
}
126+
127+
private string UnityInternalLogModeToLogType(int mode) => mode switch
128+
{
129+
_ when (mode & (int)LogMessageFlags.ScriptingError) != 0 => "error",
130+
_ when (mode & (int)LogMessageFlags.ScriptingWarning) != 0 => "warning",
131+
_ when (mode & (int)LogMessageFlags.ScriptingLog) != 0 => "log",
132+
_ when (mode & (int)LogMessageFlags.ScriptCompileError) != 0 => "compile-error",
133+
_ when (mode & (int)LogMessageFlags.ScriptCompileWarning) != 0 => "compile-warning",
134+
_ => "unknown"
135+
};
42136
}
43137
}

0 commit comments

Comments
 (0)