diff --git a/UnityMcpBridge/Editor/Helpers/TelemetryHelper.cs b/UnityMcpBridge/Editor/Helpers/TelemetryHelper.cs index 079ca6f..d15af82 100644 --- a/UnityMcpBridge/Editor/Helpers/TelemetryHelper.cs +++ b/UnityMcpBridge/Editor/Helpers/TelemetryHelper.cs @@ -12,6 +12,7 @@ namespace MCPForUnity.Editor.Helpers { private const string TELEMETRY_DISABLED_KEY = "MCPForUnity.TelemetryDisabled"; private const string CUSTOMER_UUID_KEY = "MCPForUnity.CustomerUUID"; + private static Action> s_sender; /// /// Check if telemetry is enabled (can be disabled via Environment Variable or EditorPrefs) @@ -34,7 +35,15 @@ namespace MCPForUnity.Editor.Helpers { return false; } - + + // Honor protocol-wide opt-out as well + var mcpDisable = Environment.GetEnvironmentVariable("MCP_DISABLE_TELEMETRY"); + if (!string.IsNullOrEmpty(mcpDisable) && + (mcpDisable.Equals("true", StringComparison.OrdinalIgnoreCase) || mcpDisable == "1")) + { + return false; + } + // Check EditorPrefs return !UnityEditor.EditorPrefs.GetBool(TELEMETRY_DISABLED_KEY, false); } @@ -110,6 +119,14 @@ namespace MCPForUnity.Editor.Helpers } } + /// + /// Allows the bridge to register a concrete sender for telemetry payloads. + /// + public static void RegisterTelemetrySender(Action> sender) + { + s_sender = sender; + } + /// /// Record bridge startup event /// @@ -162,15 +179,28 @@ namespace MCPForUnity.Editor.Helpers private static void SendTelemetryToPythonServer(Dictionary telemetryData) { - // This would integrate with the existing bridge communication system - // For now, we'll just log it when debug is enabled + var sender = s_sender; + if (sender != null) + { + try + { + sender(telemetryData); + return; + } + catch (Exception e) + { + if (IsDebugEnabled()) + { + Debug.LogWarning($"Telemetry sender error (non-blocking): {e.Message}"); + } + } + } + + // Fallback: log when debug is enabled if (IsDebugEnabled()) { Debug.Log($"MCP-TELEMETRY: {telemetryData["event_type"]}"); } - - // TODO: Integrate with MCPForUnityBridge command system - // We would send this as a special telemetry command to the Python server } private static bool IsDebugEnabled() diff --git a/UnityMcpBridge/UnityMcpServer~/src/server-version.txt b/UnityMcpBridge/UnityMcpServer~/src/server-version.txt new file mode 100644 index 0000000..15a2799 --- /dev/null +++ b/UnityMcpBridge/UnityMcpServer~/src/server-version.txt @@ -0,0 +1 @@ +3.3.0 diff --git a/UnityMcpBridge/UnityMcpServer~/src/server.py b/UnityMcpBridge/UnityMcpServer~/src/server.py index 08570bb..cda5f3f 100644 --- a/UnityMcpBridge/UnityMcpServer~/src/server.py +++ b/UnityMcpBridge/UnityMcpServer~/src/server.py @@ -27,8 +27,15 @@ async def server_lifespan(server: FastMCP) -> AsyncIterator[Dict[str, Any]]: # Record server startup telemetry start_time = time.time() + start_clk = time.perf_counter() + try: + from pathlib import Path + ver_path = Path(__file__).parent / "server-version.txt" + server_version = ver_path.read_text(encoding="utf-8").strip() + except Exception: + server_version = "unknown" record_telemetry(RecordType.STARTUP, { - "server_version": "3.0.2", + "server_version": server_version, "startup_time": start_time }) @@ -45,15 +52,23 @@ async def server_lifespan(server: FastMCP) -> AsyncIterator[Dict[str, Any]]: "connection_time_ms": (time.time() - start_time) * 1000 }) - except Exception as e: - logger.warning(f"Could not connect to Unity on startup: {str(e)}") + except ConnectionError as e: + logger.warning("Could not connect to Unity on startup: %s", e) _unity_connection = None # Record connection failure record_telemetry(RecordType.UNITY_CONNECTION, { "status": "failed", "error": str(e)[:200], - "connection_time_ms": (time.time() - start_time) * 1000 + "connection_time_ms": (time.perf_counter() - start_clk) * 1000 + }) + except Exception as e: + logger.warning("Unexpected error connecting to Unity on startup: %s", e) + _unity_connection = None + record_telemetry(RecordType.UNITY_CONNECTION, { + "status": "failed", + "error": str(e)[:200], + "connection_time_ms": (time.perf_counter() - start_clk) * 1000 }) try: diff --git a/UnityMcpBridge/UnityMcpServer~/src/telemetry.py b/UnityMcpBridge/UnityMcpServer~/src/telemetry.py index 7399107..fd9e82c 100644 --- a/UnityMcpBridge/UnityMcpServer~/src/telemetry.py +++ b/UnityMcpBridge/UnityMcpServer~/src/telemetry.py @@ -157,6 +157,7 @@ class TelemetryCollector: self.config = TelemetryConfig() self._customer_uuid: Optional[str] = None self._milestones: Dict[str, Dict[str, Any]] = {} + self._lock: threading.Lock = threading.Lock() self._load_persistent_data() def _load_persistent_data(self): @@ -199,18 +200,16 @@ class TelemetryCollector: """Record a milestone event, returns True if this is the first occurrence""" if not self.config.enabled: return False - milestone_key = milestone.value - if milestone_key in self._milestones: - return False # Already recorded - - milestone_data = { - "timestamp": time.time(), - "data": data or {} - } - - self._milestones[milestone_key] = milestone_data - self._save_milestones() + with self._lock: + if milestone_key in self._milestones: + return False # Already recorded + milestone_data = { + "timestamp": time.time(), + "data": data or {}, + } + self._milestones[milestone_key] = milestone_data + self._save_milestones() # Also send as telemetry record self.record(