Skip to content

Commit db8e5bc

Browse files
committed
refactor(visualScripting): expand templates and add utility functions
- Add new AI and NPC behaviors, including NPC Patrol Behavior template - Introduce UI Interaction Systems with detailed button interaction template - Implement Audio System template with background music and SFX sources - Create Particle Effect System template with configurable emission and colors - Enhance visual scripting template data with tags, category, and ordering - Add utility functions to filter templates by category, tag, and relevance - Provide functions to get all template categories and tags, with sorting - Implement search by name, description, or tags for flexible template lookup - Add template validation function ensuring structure correctness - Provide template statistics including counts by category and tag popularity - Add function to get a random template, optionally filtered by category fix(unitybridge): improve error handling and logging in bridge - Add detailed exception logging when stopping HTTP listener fails - Improve SSE client connection removal with error catching and logging - Optimize client-side logging to avoid redundant JSON stringification - Update error message handling in tool call catch block for clarity chore(server): remove ESLint config and add eventsource types - Delete server/.eslintrc.json to clean up configuration files - Add @types/eventsource as a dev dependency in package.json and lockfile docs(server): add comprehensive type definitions for Unity MCP - Provide extensive global and module type declarations for MCP usage - Define Unity-specific types for vectors, colors, bounds, and components - Include MCP tool argument, result, and resource type definitions - Add error context, retry config, environment parser, and logging types - Export all types for use in downstream modules and tools fix(readme): correct MCP server startup path - Update MCP server startup command path from PathToFile/MCP to PathToFile/server - Ensure consistent path for server execution according to current folder structure
1 parent a176542 commit db8e5bc

File tree

11 files changed

+1661
-30
lines changed

11 files changed

+1661
-30
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ The server includes automatic console verification. Configure with environment v
150150
{
151151
"unity-mcp": {
152152
"command": "node",
153-
"args": ["PathToFile/MCP/server/dist/index.js"],
153+
"args": ["PathToFile/server/dist/index.js"],
154154
"env": {
155155
"UNITY_BRIDGE_URL": "http://127.0.0.1:58888",
156156
"UNITY_CONSOLE_VERIFICATION": "true",

UnityBridge/Packages/com.example.mcp.unitybridge/Runtime/Editor/UnityMcpBridge.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,10 @@ private static void StopServer()
136136
}
137137
_listener.Close();
138138
}
139-
catch { }
139+
catch (Exception ex)
140+
{
141+
Debug.LogError($"[MCP Bridge] Failed to stop HTTP listener: {ex.Message}");
142+
}
140143
finally
141144
{
142145
_listener = null;
@@ -177,7 +180,6 @@ private static async void HandleContext(HttpListenerContext ctx)
177180
{
178181
body = await reader.ReadToEndAsync();
179182
}
180-
try { LogBridge($"-> {path} {Trunc(body, 512)}"); } catch { }
181183

182184
if (path == "/menu/execute" || path == "/editor/executeMenuItem")
183185
{
@@ -1271,8 +1273,14 @@ private static void BroadcastSse(string line)
12711273
{
12721274
lock (SseLock)
12731275
{
1274-
try { res.OutputStream.Close(); } catch { }
1275-
SseClients.Remove(res);
1276+
try
1277+
{
1278+
SseClients.Remove(res);
1279+
}
1280+
catch (Exception ex)
1281+
{
1282+
Debug.LogError($"[MCP Bridge] Failed to close SSE client connection: {ex.Message}");
1283+
}
12761284
}
12771285
}
12781286
});

client/src/client.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,11 @@ async function main() {
4747
const call = async (name: string, args: Record<string, unknown> = {}): Promise<McpResult | null> => {
4848
try {
4949
const res = await client.callTool({ name, arguments: args }) as McpResult;
50-
console.log(`${name} ${JSON.stringify(args)} ->`, JSON.stringify(res));
50+
// Optimize logging: avoid double JSON.stringify
51+
const argsStr = Object.keys(args).length === 0 ? "{}" : JSON.stringify(args);
52+
const resStr = getFirstText(res) || "[no content]";
53+
console.log(`${name} ${argsStr} -> ${resStr.length > 200 ? resStr.substring(0, 200) + "..." : resStr}`);
54+
5155
// After every tool call (except console read itself), read Unity console and print delta
5256
if (!(name === "unity_console" && (args as Record<string, unknown>)?.action === "read")) {
5357
try {
@@ -66,7 +70,7 @@ async function main() {
6670
}
6771
return res;
6872
} catch (e) {
69-
console.warn(`${name} failed:`, JSON.stringify(e, null, 2));
73+
console.warn(`${name} failed:`, (e as Error).message);
7074
return null;
7175
}
7276
};

server/.eslintrc.json

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

server/package-lock.json

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

server/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
},
2121
"devDependencies": {
2222
"@eslint/js": "^9.33.0",
23+
"@types/eventsource": "^1.1.15",
2324
"@types/jest": "^29.5.14",
2425
"@types/node": "^20.12.7",
2526
"eslint": "^9.33.0",

server/src/config.ts

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
/**
2+
* Centralized configuration management for Unity MCP Server
3+
* Handles all environment variables and configuration constants
4+
*/
5+
6+
/**
7+
* Helper function to parse boolean environment variables
8+
* @param name - Environment variable name
9+
* @param defaultValue - Default value if variable is not set or invalid
10+
* @returns Parsed boolean value
11+
*/
12+
function envBool(name: string, defaultValue: boolean): boolean {
13+
const v = (process.env[name] ?? "").toString().trim().toLowerCase();
14+
if (v === "" || v == null) return defaultValue;
15+
if (["1", "true", "yes", "on"].includes(v)) return true;
16+
if (["0", "false", "no", "off"].includes(v)) return false;
17+
return defaultValue;
18+
}
19+
20+
/**
21+
* Helper function to parse integer environment variables
22+
* @param name - Environment variable name
23+
* @param defaultValue - Default value if variable is not set or invalid
24+
* @returns Parsed integer value, or defaultValue if invalid
25+
*/
26+
function envInt(name: string, defaultValue: number): number {
27+
const raw = process.env[name];
28+
const parsed = raw != null ? Number(raw) : NaN;
29+
return Number.isFinite(parsed) && parsed >= 0 ? parsed : defaultValue;
30+
}
31+
32+
/**
33+
* Helper function to parse string environment variables with defaults
34+
* @param name - Environment variable name
35+
* @param defaultValue - Default value if variable is not set
36+
* @returns The string value or defaultValue
37+
*/
38+
function envString(name: string, defaultValue: string): string {
39+
return process.env[name] ?? defaultValue;
40+
}
41+
42+
/**
43+
* Application configuration constants
44+
*/
45+
export const CONFIG = {
46+
// Unity Bridge Configuration
47+
UNITY_BASE_URL: envString("UNITY_BRIDGE_URL", "http://127.0.0.1:58888"),
48+
UNITY_BRIDGE_TOKEN: envString("UNITY_BRIDGE_TOKEN", ""),
49+
50+
// Debug and Logging
51+
DEBUG: envBool("UNITY_MCP_DEBUG", false) || envBool("DEBUG", false),
52+
53+
// Console Verification
54+
CONSOLE_VERIFICATION_ENABLED: envBool("UNITY_CONSOLE_VERIFICATION", true),
55+
CONSOLE_CHECK_DELAY_MS: envInt("UNITY_CONSOLE_CHECK_DELAY_MS", 500),
56+
CONSOLE_MAX_LINES: envInt("UNITY_CONSOLE_MAX_LINES", 100),
57+
58+
// Compilation and Timeouts
59+
COMPILE_TIMEOUT_MS: envInt("UNITY_COMPILE_TIMEOUT_MS", 120_000),
60+
DEFAULT_HTTP_TIMEOUT_MS: 45_000,
61+
GET_TIMEOUT_MS: 30_000,
62+
63+
// Network Configuration
64+
MAX_RETRY_ATTEMPTS: envInt("UNITY_MAX_RETRY_ATTEMPTS", 8),
65+
RETRY_BASE_DELAY_MS: envInt("UNITY_RETRY_BASE_DELAY_MS", 200),
66+
MAX_RETRY_DELAY_MS: envInt("UNITY_MAX_RETRY_DELAY_MS", 5000),
67+
68+
// Application Metadata
69+
APP_NAME: "unity-mcp",
70+
APP_VERSION: "0.1.0",
71+
72+
// Performance Monitoring
73+
ENABLE_PERFORMANCE_MONITORING: envBool("UNITY_PERFORMANCE_MONITORING", false),
74+
PERFORMANCE_LOG_INTERVAL_MS: envInt("UNITY_PERFORMANCE_LOG_INTERVAL", 10000),
75+
76+
// Error Messages
77+
ERROR_MESSAGES: {
78+
UNITY_NOT_RUNNING: "Unity Editor is not running or Unity Bridge is not accessible",
79+
UNAUTHORIZED: "Unauthorized: Set UNITY_BRIDGE_TOKEN in both Unity and server",
80+
COMPILATION_TIMEOUT: "Timed out waiting for Unity to finish compilation",
81+
INVALID_OPERATION: "Invalid operation or parameters",
82+
} as const,
83+
84+
// Resource URIs
85+
RESOURCES: {
86+
UNITY_LOGS: "unity://logs",
87+
} as const,
88+
} as const;
89+
90+
/**
91+
* Type-safe configuration access
92+
*/
93+
export type AppConfig = typeof CONFIG;
94+
95+
/**
96+
* Validates the current configuration and logs warnings for missing required values
97+
* @returns True if configuration is valid, false if critical issues found
98+
*/
99+
export function validateConfig(): boolean {
100+
let isValid = true;
101+
102+
// Validate Unity Bridge Configuration
103+
if (!CONFIG.UNITY_BRIDGE_TOKEN) {
104+
console.warn("[unity-mcp] UNITY_BRIDGE_TOKEN not set; the bridge will accept unauthenticated requests on 127.0.0.1. Set a token in both Unity and server env for security.");
105+
}
106+
107+
// Validate URL format
108+
try {
109+
new URL(CONFIG.UNITY_BASE_URL);
110+
} catch {
111+
console.error("[unity-mcp] UNITY_BRIDGE_URL is not a valid URL:", CONFIG.UNITY_BASE_URL);
112+
isValid = false;
113+
}
114+
115+
// Validate timeout configurations
116+
if (CONFIG.COMPILE_TIMEOUT_MS < 10000) {
117+
console.warn("[unity-mcp] COMPILE_TIMEOUT_MS is very low:", CONFIG.COMPILE_TIMEOUT_MS, "ms. Consider increasing to at least 10000ms.");
118+
}
119+
120+
if (CONFIG.DEFAULT_HTTP_TIMEOUT_MS < 5000) {
121+
console.warn("[unity-mcp] DEFAULT_HTTP_TIMEOUT_MS is low:", CONFIG.DEFAULT_HTTP_TIMEOUT_MS, "ms. Consider increasing for stability.");
122+
}
123+
124+
// Validate retry configuration
125+
if (CONFIG.MAX_RETRY_ATTEMPTS < 1) {
126+
console.error("[unity-mcp] MAX_RETRY_ATTEMPTS must be at least 1");
127+
isValid = false;
128+
}
129+
130+
if (CONFIG.RETRY_BASE_DELAY_MS < 50) {
131+
console.warn("[unity-mcp] RETRY_BASE_DELAY_MS is very low:", CONFIG.RETRY_BASE_DELAY_MS, "ms. This may cause rapid retry storms.");
132+
}
133+
134+
if (CONFIG.MAX_RETRY_DELAY_MS < CONFIG.RETRY_BASE_DELAY_MS) {
135+
console.error("[unity-mcp] MAX_RETRY_DELAY_MS should be greater than RETRY_BASE_DELAY_MS");
136+
isValid = false;
137+
}
138+
139+
// Validate console configuration
140+
if (CONFIG.CONSOLE_MAX_LINES < 10) {
141+
console.warn("[unity-mcp] CONSOLE_MAX_LINES is very low:", CONFIG.CONSOLE_MAX_LINES, "lines. Consider increasing for better debugging.");
142+
}
143+
144+
// Log configuration in debug mode
145+
if (CONFIG.DEBUG) {
146+
console.log("[unity-mcp] Debug mode enabled");
147+
console.log("[unity-mcp] Configuration:", {
148+
UNITY_BASE_URL: CONFIG.UNITY_BASE_URL,
149+
CONSOLE_VERIFICATION_ENABLED: CONFIG.CONSOLE_VERIFICATION_ENABLED,
150+
COMPILE_TIMEOUT_MS: CONFIG.COMPILE_TIMEOUT_MS,
151+
MAX_RETRY_ATTEMPTS: CONFIG.MAX_RETRY_ATTEMPTS,
152+
ENABLE_PERFORMANCE_MONITORING: CONFIG.ENABLE_PERFORMANCE_MONITORING,
153+
});
154+
}
155+
156+
return isValid;
157+
}

0 commit comments

Comments
 (0)