Skip to content

Commit cb5f0dd

Browse files
Merge pull request #44 from Saqoosha/feature/console-logs-stacktrace-option
feat: Add includeStackTrace option to reduce LLM token usage by 80-90%
2 parents b4b4bd6 + 7c14c02 commit cb5f0dd

File tree

7 files changed

+96
-38
lines changed

7 files changed

+96
-38
lines changed

Editor/Resources/GetConsoleLogsResource.cs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public class GetConsoleLogsResource : McpResourceBase
1414
public GetConsoleLogsResource(IConsoleLogsService consoleLogsService)
1515
{
1616
Name = "get_console_logs";
17-
Description = "Retrieves logs from the Unity console (newest first), optionally filtered by type (error, warning, info). Use pagination parameters (offset, limit) to avoid LLM token limits. Recommended: limit=20-50 for optimal performance.";
17+
Description = "Retrieves logs from the Unity console (newest first), optionally filtered by type (error, warning, info). Use pagination parameters (offset, limit) to avoid LLM token limits. Set includeStackTrace=false to exclude stack traces and reduce token usage. Recommended: limit=20-50 for optimal performance.";
1818
Uri = "unity://logs/{logType}";
1919

2020
_consoleLogsService = consoleLogsService;
@@ -32,17 +32,20 @@ public override JObject Fetch(JObject parameters)
3232

3333
int offset = Math.Max(0, GetIntParameter(parameters, "offset", 0));
3434
int limit = Math.Max(1, Math.Min(1000, GetIntParameter(parameters, "limit", 100)));
35+
bool includeStackTrace = GetBoolParameter(parameters, "includeStackTrace", true);
36+
37+
// Debug logging - temporarily remove to avoid console clutter
3538

36-
// Use the new paginated method
37-
JObject result = _consoleLogsService.GetLogsAsJson(logType, offset, limit);
39+
// Use the new paginated method with stack trace option
40+
JObject result = _consoleLogsService.GetLogsAsJson(logType, offset, limit, includeStackTrace);
3841

3942
// Add formatted message with pagination info
4043
string typeFilter = logType != null ? $" of type '{logType}'" : "";
4144
int returnedCount = result["_returnedCount"]?.Value<int>() ?? 0;
4245
int filteredCount = result["_filteredCount"]?.Value<int>() ?? 0;
4346
int totalCount = result["_totalCount"]?.Value<int>() ?? 0;
4447

45-
result["message"] = $"Retrieved {returnedCount} of {filteredCount} log entries{typeFilter} (offset: {offset}, limit: {limit}, total: {totalCount})";
48+
result["message"] = $"Retrieved {returnedCount} of {filteredCount} log entries{typeFilter} (offset: {offset}, limit: {limit}, includeStackTrace: {includeStackTrace}, total: {totalCount})";
4649
result["success"] = true;
4750

4851
// Remove internal count fields (they're now in the message)
@@ -67,6 +70,20 @@ private static int GetIntParameter(JObject parameters, string key, int defaultVa
6770
return defaultValue;
6871
}
6972

73+
/// <summary>
74+
/// Helper method to safely extract boolean parameters with default values
75+
/// </summary>
76+
/// <param name="parameters">JObject containing parameters</param>
77+
/// <param name="key">Parameter key to extract</param>
78+
/// <param name="defaultValue">Default value if parameter is missing or invalid</param>
79+
/// <returns>Extracted boolean value or default</returns>
80+
private static bool GetBoolParameter(JObject parameters, string key, bool defaultValue)
81+
{
82+
if (parameters?[key] != null && bool.TryParse(parameters[key].ToString(), out bool value))
83+
return value;
84+
return defaultValue;
85+
}
86+
7087

7188
}
7289
}

Editor/Services/ConsoleLogsService.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,9 @@ public void StopListening()
8383
/// <param name="logType">Filter by log type (empty for all)</param>
8484
/// <param name="offset">Starting index (0-based)</param>
8585
/// <param name="limit">Maximum number of logs to return (default: 100)</param>
86+
/// <param name="includeStackTrace">Whether to include stack trace in logs (default: true)</param>
8687
/// <returns>JObject containing logs array and pagination info</returns>
87-
public JObject GetLogsAsJson(string logType = "", int offset = 0, int limit = 100)
88+
public JObject GetLogsAsJson(string logType = "", int offset = 0, int limit = 100, bool includeStackTrace = true)
8889
{
8990
// Convert log entries to a JSON array, filtering by logType if provided
9091
JArray logsArray = new JArray();
@@ -127,13 +128,20 @@ public JObject GetLogsAsJson(string logType = "", int offset = 0, int limit = 10
127128
// Check if we're in the offset range and haven't reached the limit yet
128129
if (currentIndex >= offset && logsArray.Count < limit)
129130
{
130-
logsArray.Add(new JObject
131+
var logObject = new JObject
131132
{
132133
["message"] = entry.Message,
133-
["stackTrace"] = entry.StackTrace,
134134
["type"] = entry.Type.ToString(),
135135
["timestamp"] = entry.Timestamp.ToString("yyyy-MM-dd HH:mm:ss.fff")
136-
});
136+
};
137+
138+
// Only include stack trace if requested
139+
if (includeStackTrace)
140+
{
141+
logObject["stackTrace"] = entry.StackTrace;
142+
}
143+
144+
logsArray.Add(logObject);
137145
}
138146

139147
currentIndex++;

Editor/Services/IConsoleLogsService.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@ public interface IConsoleLogsService
1616
/// <param name="logType">Filter by log type (empty for all)</param>
1717
/// <param name="offset">Starting index (0-based)</param>
1818
/// <param name="limit">Maximum number of logs to return (default: 100)</param>
19+
/// <param name="includeStackTrace">Whether to include stack trace in logs (default: true)</param>
1920
/// <returns>JObject containing logs array and pagination info</returns>
20-
JObject GetLogsAsJson(string logType = "", int offset = 0, int limit = 100);
21+
JObject GetLogsAsJson(string logType = "", int offset = 0, int limit = 100, bool includeStackTrace = true);
2122

2223
/// <summary>
2324
/// Start listening for logs

Server~/build/resources/getConsoleLogsResource.js

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,35 +3,35 @@ import { McpUnityError, ErrorType } from '../utils/errors.js';
33
// Constants for the resource
44
const resourceName = 'get_console_logs';
55
const resourceMimeType = 'application/json';
6-
const resourceUri = 'unity://logs/{logType}?offset={offset}&limit={limit}';
6+
const resourceUri = 'unity://logs/{logType}?offset={offset}&limit={limit}&includeStackTrace={includeStackTrace}';
77
const resourceTemplate = new ResourceTemplate(resourceUri, {
88
list: () => listLogTypes(resourceMimeType)
99
});
1010
function listLogTypes(resourceMimeType) {
1111
return {
1212
resources: [
1313
{
14-
uri: `unity://logs/`,
14+
uri: `unity://logs/?offset=0&limit=50&includeStackTrace=true`,
1515
name: "All logs",
16-
description: "Retrieve Unity console logs (newest first). Use pagination to avoid token limits: ?offset=0&limit=50 for recent logs. Default limit=100 may be too large for LLM context.",
16+
description: "All Unity console logs (newest first). ⚠️ Set includeStackTrace=false to save 80-90% tokens. Use limit=50 to avoid token limits.",
1717
mimeType: resourceMimeType
1818
},
1919
{
20-
uri: `unity://logs/error`,
20+
uri: `unity://logs/error?offset=0&limit=20&includeStackTrace=true`,
2121
name: "Error logs",
22-
description: "Retrieve only error logs from Unity console (newest first). Use ?offset=0&limit=20 to avoid token limits. Large log sets may exceed LLM context window.",
22+
description: "Error logs only. ⚠️ Start with includeStackTrace=false for quick overview, then true only if debugging specific errors.",
2323
mimeType: resourceMimeType
2424
},
2525
{
26-
uri: `unity://logs/warning`,
26+
uri: `unity://logs/warning?offset=0&limit=30&includeStackTrace=true`,
2727
name: "Warning logs",
28-
description: "Retrieve only warning logs from Unity console (newest first). Use pagination ?offset=0&limit=30 to manage token usage effectively.",
28+
description: "Warning logs only. ⚠️ Use includeStackTrace=false by default to save tokens.",
2929
mimeType: resourceMimeType
3030
},
3131
{
32-
uri: `unity://logs/info`,
32+
uri: `unity://logs/info?offset=0&limit=25&includeStackTrace=false`,
3333
name: "Info logs",
34-
description: "Retrieve only info logs from Unity console (newest first). Use smaller limits like ?limit=25 to prevent token overflow in LLM responses.",
34+
description: "Info logs only. Stack traces excluded by default to minimize tokens.",
3535
mimeType: resourceMimeType
3636
}
3737
]
@@ -43,7 +43,7 @@ function listLogTypes(resourceMimeType) {
4343
export function registerGetConsoleLogsResource(server, mcpUnity, logger) {
4444
logger.info(`Registering resource: ${resourceName}`);
4545
server.resource(resourceName, resourceTemplate, {
46-
description: 'Retrieve Unity console logs by type (newest first). IMPORTANT: Use pagination parameters ?offset=0&limit=50 to avoid LLM token limits. Default limit=100 may exceed context window.',
46+
description: 'Retrieve Unity console logs by type with pagination support. See individual log type descriptions for optimal settings.',
4747
mimeType: resourceMimeType
4848
}, async (uri, variables) => {
4949
try {
@@ -63,24 +63,38 @@ async function resourceHandler(mcpUnity, uri, variables, logger) {
6363
let logType = variables["logType"] ? decodeURIComponent(variables["logType"]) : undefined;
6464
if (logType === '')
6565
logType = undefined;
66-
// Extract pagination parameters
66+
// Extract pagination parameters with validation
6767
const offset = variables["offset"] ? parseInt(variables["offset"], 10) : 0;
6868
const limit = variables["limit"] ? parseInt(variables["limit"], 10) : 100;
69+
// Extract includeStackTrace parameter
70+
let includeStackTrace = true; // Default to true for backward compatibility
71+
if (variables["includeStackTrace"] !== undefined) {
72+
const value = variables["includeStackTrace"];
73+
includeStackTrace = value === 'true' || value === '1' || value === 'yes';
74+
}
75+
// Validate pagination parameters
76+
if (isNaN(offset) || offset < 0) {
77+
throw new McpUnityError(ErrorType.VALIDATION, 'Invalid offset parameter: must be a non-negative integer');
78+
}
79+
if (isNaN(limit) || limit <= 0) {
80+
throw new McpUnityError(ErrorType.VALIDATION, 'Invalid limit parameter: must be a positive integer');
81+
}
6982
// Send request to Unity
7083
const response = await mcpUnity.sendRequest({
7184
method: resourceName,
7285
params: {
7386
logType: logType,
7487
offset: offset,
75-
limit: limit
88+
limit: limit,
89+
includeStackTrace: includeStackTrace
7690
}
7791
});
7892
if (!response.success) {
7993
throw new McpUnityError(ErrorType.RESOURCE_FETCH, response.message || 'Failed to fetch logs from Unity');
8094
}
8195
return {
8296
contents: [{
83-
uri: `unity://logs/${logType ?? ''}?offset=${offset}&limit=${limit}`,
97+
uri: `unity://logs/${logType ?? ''}?offset=${offset}&limit=${limit}&includeStackTrace=${includeStackTrace}`,
8498
mimeType: resourceMimeType,
8599
text: JSON.stringify(response, null, 2)
86100
}]

Server~/build/tools/getConsoleLogsTool.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@ const paramsSchema = z.object({
2020
.min(1)
2121
.max(500)
2222
.optional()
23-
.describe("Maximum number of logs to return (defaults to 50, max 500 to avoid token limits)")
23+
.describe("Maximum number of logs to return (defaults to 50, max 500 to avoid token limits)"),
24+
includeStackTrace: z
25+
.boolean()
26+
.optional()
27+
.describe("Whether to include stack trace in logs. ⚠️ ALWAYS SET TO FALSE to save 80-90% tokens, unless you specifically need stack traces for debugging. Default: true (except info logs in resource)")
2428
});
2529
/**
2630
* Creates and registers the Get Console Logs tool with the MCP server
@@ -55,7 +59,7 @@ export function registerGetConsoleLogsTool(server, mcpUnity, logger) {
5559
* @throws McpUnityError if the request to Unity fails
5660
*/
5761
async function toolHandler(mcpUnity, params) {
58-
const { logType, offset = 0, limit = 50 } = params;
62+
const { logType, offset = 0, limit = 50, includeStackTrace = true } = params;
5963
// Send request to Unity using the same method name as the resource
6064
// This allows reusing the existing Unity-side implementation
6165
const response = await mcpUnity.sendRequest({
@@ -64,6 +68,7 @@ async function toolHandler(mcpUnity, params) {
6468
logType: logType,
6569
offset: offset,
6670
limit: limit,
71+
includeStackTrace: includeStackTrace,
6772
},
6873
});
6974
if (!response.success) {

Server~/src/resources/getConsoleLogsResource.ts

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { Variables } from '@modelcontextprotocol/sdk/shared/uriTemplate.js';
88
// Constants for the resource
99
const resourceName = 'get_console_logs';
1010
const resourceMimeType = 'application/json';
11-
const resourceUri = 'unity://logs/{logType}?offset={offset}&limit={limit}';
11+
const resourceUri = 'unity://logs/{logType}?offset={offset}&limit={limit}&includeStackTrace={includeStackTrace}';
1212
const resourceTemplate = new ResourceTemplate(resourceUri, {
1313
list: () => listLogTypes(resourceMimeType)
1414
});
@@ -17,27 +17,27 @@ function listLogTypes(resourceMimeType: string) {
1717
return {
1818
resources: [
1919
{
20-
uri: `unity://logs/?offset=0&limit=50`,
20+
uri: `unity://logs/?offset=0&limit=50&includeStackTrace=true`,
2121
name: "All logs",
22-
description: "Retrieve Unity console logs (newest first). Default pagination offset=0&limit=50 to avoid token limits.",
22+
description: "All Unity console logs (newest first). ⚠️ Set includeStackTrace=false to save 80-90% tokens. Use limit=50 to avoid token limits.",
2323
mimeType: resourceMimeType
2424
},
2525
{
26-
uri: `unity://logs/error?offset=0&limit=20`,
26+
uri: `unity://logs/error?offset=0&limit=20&includeStackTrace=true`,
2727
name: "Error logs",
28-
description: "Retrieve only error logs from Unity console (newest first). Default pagination offset=0&limit=20.",
28+
description: "Error logs only. ⚠️ Start with includeStackTrace=false for quick overview, then true only if debugging specific errors.",
2929
mimeType: resourceMimeType
3030
},
3131
{
32-
uri: `unity://logs/warning?offset=0&limit=30`,
32+
uri: `unity://logs/warning?offset=0&limit=30&includeStackTrace=true`,
3333
name: "Warning logs",
34-
description: "Retrieve only warning logs from Unity console (newest first). Default pagination offset=0&limit=30.",
34+
description: "Warning logs only. ⚠️ Use includeStackTrace=false by default to save tokens.",
3535
mimeType: resourceMimeType
3636
},
3737
{
38-
uri: `unity://logs/info?offset=0&limit=25`,
38+
uri: `unity://logs/info?offset=0&limit=25&includeStackTrace=false`,
3939
name: "Info logs",
40-
description: "Retrieve only info logs from Unity console (newest first). Default pagination offset=0&limit=25.",
40+
description: "Info logs only. Stack traces excluded by default to minimize tokens.",
4141
mimeType: resourceMimeType
4242
}
4343
]
@@ -54,7 +54,7 @@ export function registerGetConsoleLogsResource(server: McpServer, mcpUnity: McpU
5454
resourceName,
5555
resourceTemplate,
5656
{
57-
description: 'Retrieve Unity console logs by type (newest first). IMPORTANT: Use pagination parameters ?offset=0&limit=50 to avoid LLM token limits. Default limit=100 may exceed context window.',
57+
description: 'Retrieve Unity console logs by type with pagination support. See individual log type descriptions for optimal settings.',
5858
mimeType: resourceMimeType
5959
},
6060
async (uri, variables) => {
@@ -80,6 +80,13 @@ async function resourceHandler(mcpUnity: McpUnity, uri: URL, variables: Variable
8080
const offset = variables["offset"] ? parseInt(variables["offset"] as string, 10) : 0;
8181
const limit = variables["limit"] ? parseInt(variables["limit"] as string, 10) : 100;
8282

83+
// Extract includeStackTrace parameter
84+
let includeStackTrace = true; // Default to true for backward compatibility
85+
if (variables["includeStackTrace"] !== undefined) {
86+
const value = variables["includeStackTrace"] as string;
87+
includeStackTrace = value === 'true' || value === '1' || value === 'yes';
88+
}
89+
8390
// Validate pagination parameters
8491
if (isNaN(offset) || offset < 0) {
8592
throw new McpUnityError(ErrorType.VALIDATION, 'Invalid offset parameter: must be a non-negative integer');
@@ -94,7 +101,8 @@ async function resourceHandler(mcpUnity: McpUnity, uri: URL, variables: Variable
94101
params: {
95102
logType: logType,
96103
offset: offset,
97-
limit: limit
104+
limit: limit,
105+
includeStackTrace: includeStackTrace
98106
}
99107
});
100108

@@ -107,7 +115,7 @@ async function resourceHandler(mcpUnity: McpUnity, uri: URL, variables: Variable
107115

108116
return {
109117
contents: [{
110-
uri: `unity://logs/${logType ?? ''}?offset=${offset}&limit=${limit}`,
118+
uri: `unity://logs/${logType ?? ''}?offset=${offset}&limit=${limit}&includeStackTrace=${includeStackTrace}`,
111119
mimeType: resourceMimeType,
112120
text: JSON.stringify(response, null, 2)
113121
}]

Server~/src/tools/getConsoleLogsTool.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,11 @@ const paramsSchema = z.object({
2727
.min(1)
2828
.max(500)
2929
.optional()
30-
.describe("Maximum number of logs to return (defaults to 50, max 500 to avoid token limits)")
30+
.describe("Maximum number of logs to return (defaults to 50, max 500 to avoid token limits)"),
31+
includeStackTrace: z
32+
.boolean()
33+
.optional()
34+
.describe("Whether to include stack trace in logs. ⚠️ ALWAYS SET TO FALSE to save 80-90% tokens, unless you specifically need stack traces for debugging. Default: true (except info logs in resource)")
3135
});
3236

3337
/**
@@ -76,7 +80,7 @@ async function toolHandler(
7680
mcpUnity: McpUnity,
7781
params: z.infer<typeof paramsSchema>
7882
): Promise<CallToolResult> {
79-
const { logType, offset = 0, limit = 50 } = params;
83+
const { logType, offset = 0, limit = 50, includeStackTrace = true } = params;
8084

8185
// Send request to Unity using the same method name as the resource
8286
// This allows reusing the existing Unity-side implementation
@@ -86,6 +90,7 @@ async function toolHandler(
8690
logType: logType,
8791
offset: offset,
8892
limit: limit,
93+
includeStackTrace: includeStackTrace,
8994
},
9095
});
9196

0 commit comments

Comments
 (0)