Skip to content

Commit e5039c8

Browse files
added optional telemetry
1 parent 22e8016 commit e5039c8

File tree

11 files changed

+929
-0
lines changed

11 files changed

+929
-0
lines changed

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,18 @@ Help make MCP for Unity better!
331331

332332
---
333333

334+
## 📊 Telemetry & Privacy
335+
336+
Unity MCP includes **privacy-focused, anonymous telemetry** to help us improve the product. We collect usage analytics and performance data, but **never** your code, project names, or personal information.
337+
338+
- **🔒 Anonymous**: Random UUIDs only, no personal data
339+
- **🚫 Easy opt-out**: Set `DISABLE_TELEMETRY=true` environment variable
340+
- **📖 Transparent**: See [TELEMETRY.md](TELEMETRY.md) for full details
341+
342+
Your privacy matters to us. All telemetry is optional and designed to respect your workflow.
343+
344+
---
345+
334346
## Troubleshooting ❓
335347

336348
<details>

TELEMETRY.md

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
# Unity MCP Telemetry
2+
3+
Unity MCP includes privacy-focused, anonymous telemetry to help us improve the product. This document explains what data is collected, how to opt out, and our privacy practices.
4+
5+
## 🔒 Privacy First
6+
7+
- **Anonymous**: We use randomly generated UUIDs - no personal information
8+
- **Non-blocking**: Telemetry never interferes with your Unity workflow
9+
- **Easy opt-out**: Simple environment variable or Unity Editor setting
10+
- **Transparent**: All collected data types are documented here
11+
12+
## 📊 What We Collect
13+
14+
### Usage Analytics
15+
- **Tool Usage**: Which MCP tools you use (manage_script, manage_scene, etc.)
16+
- **Performance**: Execution times and success/failure rates
17+
- **System Info**: Unity version, platform (Windows/Mac/Linux), MCP version
18+
- **Milestones**: First-time usage events (first script creation, first tool use, etc.)
19+
20+
### Technical Diagnostics
21+
- **Connection Events**: Bridge startup/connection success/failures
22+
- **Error Reports**: Anonymized error messages (truncated to 200 chars)
23+
- **Server Health**: Startup time, connection latency
24+
25+
### What We **DON'T** Collect
26+
- ❌ Your code or script contents
27+
- ❌ Project names, file names, or paths
28+
- ❌ Personal information or identifiers
29+
- ❌ Sensitive project data
30+
- ❌ IP addresses (beyond what's needed for HTTP requests)
31+
32+
## 🚫 How to Opt Out
33+
34+
### Method 1: Environment Variable (Recommended)
35+
Set any of these environment variables to `true`:
36+
37+
```bash
38+
# Disable all telemetry
39+
export DISABLE_TELEMETRY=true
40+
41+
# Unity MCP specific
42+
export UNITY_MCP_DISABLE_TELEMETRY=true
43+
44+
# MCP protocol wide
45+
export MCP_DISABLE_TELEMETRY=true
46+
```
47+
48+
### Method 2: Unity Editor (Coming Soon)
49+
In Unity Editor: `Window > MCP for Unity > Settings > Disable Telemetry`
50+
51+
### Method 3: Manual Config
52+
Add to your MCP client config:
53+
```json
54+
{
55+
"env": {
56+
"DISABLE_TELEMETRY": "true"
57+
}
58+
}
59+
```
60+
61+
## 🔧 Technical Implementation
62+
63+
### Architecture
64+
- **Python Server**: Core telemetry collection and transmission
65+
- **Unity Bridge**: Local event collection from Unity Editor
66+
- **Anonymous UUIDs**: Generated per-installation for aggregate analytics
67+
- **Thread-safe**: Non-blocking background transmission
68+
- **Fail-safe**: Errors never interrupt your workflow
69+
70+
### Data Storage
71+
Telemetry data is stored locally in:
72+
- **Windows**: `%APPDATA%\UnityMCP\`
73+
- **macOS**: `~/Library/Application Support/UnityMCP/`
74+
- **Linux**: `~/.local/share/UnityMCP/`
75+
76+
Files created:
77+
- `customer_uuid.txt`: Anonymous identifier
78+
- `milestones.json`: One-time events tracker
79+
80+
### Data Transmission
81+
- **Endpoint**: `https://telemetry.coplay.dev/unity-mcp/anonymous`
82+
- **Method**: HTTPS POST with JSON payload
83+
- **Retry**: Background thread with graceful failure
84+
- **Timeout**: 10 second timeout, no retries on failure
85+
86+
## 📈 How We Use This Data
87+
88+
### Product Improvement
89+
- **Feature Usage**: Understand which tools are most/least used
90+
- **Performance**: Identify slow operations to optimize
91+
- **Reliability**: Track error rates and connection issues
92+
- **Compatibility**: Ensure Unity version compatibility
93+
94+
### Development Priorities
95+
- **Roadmap**: Focus development on most-used features
96+
- **Bug Fixes**: Prioritize fixes based on error frequency
97+
- **Platform Support**: Allocate resources based on platform usage
98+
- **Documentation**: Improve docs for commonly problematic areas
99+
100+
### What We Don't Do
101+
- ❌ Sell data to third parties
102+
- ❌ Use data for advertising/marketing
103+
- ❌ Track individual developers
104+
- ❌ Store sensitive project information
105+
106+
## 🛠️ For Developers
107+
108+
### Testing Telemetry
109+
```bash
110+
cd UnityMcpBridge/UnityMcpServer~/src
111+
python test_telemetry.py
112+
```
113+
114+
### Custom Telemetry Events
115+
```python
116+
from telemetry import record_telemetry, RecordType
117+
118+
record_telemetry(RecordType.USAGE, {
119+
"custom_event": "my_feature_used",
120+
"metadata": "optional_data"
121+
})
122+
```
123+
124+
### Telemetry Status Check
125+
```python
126+
from telemetry import is_telemetry_enabled
127+
128+
if is_telemetry_enabled():
129+
print("Telemetry is active")
130+
else:
131+
print("Telemetry is disabled")
132+
```
133+
134+
## 📋 Data Retention Policy
135+
136+
- **Aggregated Data**: Retained indefinitely for product insights
137+
- **Raw Events**: Automatically purged after 90 days
138+
- **Personal Data**: None collected, so none to purge
139+
- **Opt-out**: Immediate - no data sent after opting out
140+
141+
## 🤝 Contact & Transparency
142+
143+
- **Questions**: [Discord Community](https://discord.gg/y4p8KfzrN4)
144+
- **Issues**: [GitHub Issues](https://github.com/CoplayDev/unity-mcp/issues)
145+
- **Privacy Concerns**: Create a GitHub issue with "Privacy" label
146+
- **Source Code**: All telemetry code is open source in this repository
147+
148+
## 📊 Example Telemetry Event
149+
150+
Here's what a typical telemetry event looks like:
151+
152+
```json
153+
{
154+
"record": "tool_execution",
155+
"timestamp": 1704067200,
156+
"customer_uuid": "550e8400-e29b-41d4-a716-446655440000",
157+
"session_id": "abc123-def456-ghi789",
158+
"version": "3.0.2",
159+
"platform": "posix",
160+
"data": {
161+
"tool_name": "manage_script",
162+
"success": true,
163+
"duration_ms": 42.5
164+
}
165+
}
166+
```
167+
168+
Notice:
169+
- ✅ Anonymous UUID (randomly generated)
170+
- ✅ Tool performance metrics
171+
- ✅ Success/failure tracking
172+
- ❌ No code content
173+
- ❌ No project information
174+
- ❌ No personal data
175+
176+
---
177+
178+
*Unity MCP Telemetry is designed to respect your privacy while helping us build a better tool. Thank you for helping improve Unity MCP!*
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using UnityEngine;
4+
5+
namespace MCPForUnity.Editor.Helpers
6+
{
7+
/// <summary>
8+
/// Unity Bridge telemetry helper for collecting usage analytics
9+
/// Following privacy-first approach with easy opt-out mechanisms
10+
/// </summary>
11+
public static class TelemetryHelper
12+
{
13+
private const string TELEMETRY_DISABLED_KEY = "MCPForUnity.TelemetryDisabled";
14+
private const string CUSTOMER_UUID_KEY = "MCPForUnity.CustomerUUID";
15+
16+
/// <summary>
17+
/// Check if telemetry is enabled (can be disabled via Environment Variable or EditorPrefs)
18+
/// </summary>
19+
public static bool IsEnabled
20+
{
21+
get
22+
{
23+
// Check environment variables first
24+
var envDisable = Environment.GetEnvironmentVariable("DISABLE_TELEMETRY");
25+
if (!string.IsNullOrEmpty(envDisable) &&
26+
(envDisable.ToLower() == "true" || envDisable == "1"))
27+
{
28+
return false;
29+
}
30+
31+
var unityMcpDisable = Environment.GetEnvironmentVariable("UNITY_MCP_DISABLE_TELEMETRY");
32+
if (!string.IsNullOrEmpty(unityMcpDisable) &&
33+
(unityMcpDisable.ToLower() == "true" || unityMcpDisable == "1"))
34+
{
35+
return false;
36+
}
37+
38+
// Check EditorPrefs
39+
return !UnityEditor.EditorPrefs.GetBool(TELEMETRY_DISABLED_KEY, false);
40+
}
41+
}
42+
43+
/// <summary>
44+
/// Get or generate customer UUID for anonymous tracking
45+
/// </summary>
46+
public static string GetCustomerUUID()
47+
{
48+
var uuid = UnityEditor.EditorPrefs.GetString(CUSTOMER_UUID_KEY, "");
49+
if (string.IsNullOrEmpty(uuid))
50+
{
51+
uuid = System.Guid.NewGuid().ToString();
52+
UnityEditor.EditorPrefs.SetString(CUSTOMER_UUID_KEY, uuid);
53+
}
54+
return uuid;
55+
}
56+
57+
/// <summary>
58+
/// Disable telemetry (stored in EditorPrefs)
59+
/// </summary>
60+
public static void DisableTelemetry()
61+
{
62+
UnityEditor.EditorPrefs.SetBool(TELEMETRY_DISABLED_KEY, true);
63+
}
64+
65+
/// <summary>
66+
/// Enable telemetry (stored in EditorPrefs)
67+
/// </summary>
68+
public static void EnableTelemetry()
69+
{
70+
UnityEditor.EditorPrefs.SetBool(TELEMETRY_DISABLED_KEY, false);
71+
}
72+
73+
/// <summary>
74+
/// Send telemetry data to Python server for processing
75+
/// This is a lightweight bridge - the actual telemetry logic is in Python
76+
/// </summary>
77+
public static void RecordEvent(string eventType, Dictionary<string, object> data = null)
78+
{
79+
if (!IsEnabled)
80+
return;
81+
82+
try
83+
{
84+
var telemetryData = new Dictionary<string, object>
85+
{
86+
["event_type"] = eventType,
87+
["timestamp"] = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
88+
["customer_uuid"] = GetCustomerUUID(),
89+
["unity_version"] = Application.unityVersion,
90+
["platform"] = Application.platform.ToString(),
91+
["source"] = "unity_bridge"
92+
};
93+
94+
if (data != null)
95+
{
96+
telemetryData["data"] = data;
97+
}
98+
99+
// Send to Python server via existing bridge communication
100+
// The Python server will handle actual telemetry transmission
101+
SendTelemetryToPythonServer(telemetryData);
102+
}
103+
catch (Exception e)
104+
{
105+
// Never let telemetry errors interfere with functionality
106+
if (IsDebugEnabled())
107+
{
108+
Debug.LogWarning($"Telemetry error (non-blocking): {e.Message}");
109+
}
110+
}
111+
}
112+
113+
/// <summary>
114+
/// Record bridge startup event
115+
/// </summary>
116+
public static void RecordBridgeStartup()
117+
{
118+
RecordEvent("bridge_startup", new Dictionary<string, object>
119+
{
120+
["bridge_version"] = "3.0.2",
121+
["auto_connect"] = MCPForUnityBridge.IsAutoConnectMode
122+
});
123+
}
124+
125+
/// <summary>
126+
/// Record bridge connection event
127+
/// </summary>
128+
public static void RecordBridgeConnection(bool success, string error = null)
129+
{
130+
var data = new Dictionary<string, object>
131+
{
132+
["success"] = success
133+
};
134+
135+
if (!string.IsNullOrEmpty(error))
136+
{
137+
data["error"] = error.Substring(0, Math.Min(200, error.Length));
138+
}
139+
140+
RecordEvent("bridge_connection", data);
141+
}
142+
143+
/// <summary>
144+
/// Record tool execution from Unity side
145+
/// </summary>
146+
public static void RecordToolExecution(string toolName, bool success, float durationMs, string error = null)
147+
{
148+
var data = new Dictionary<string, object>
149+
{
150+
["tool_name"] = toolName,
151+
["success"] = success,
152+
["duration_ms"] = Math.Round(durationMs, 2)
153+
};
154+
155+
if (!string.IsNullOrEmpty(error))
156+
{
157+
data["error"] = error.Substring(0, Math.Min(200, error.Length));
158+
}
159+
160+
RecordEvent("tool_execution_unity", data);
161+
}
162+
163+
private static void SendTelemetryToPythonServer(Dictionary<string, object> telemetryData)
164+
{
165+
// This would integrate with the existing bridge communication system
166+
// For now, we'll just log it when debug is enabled
167+
if (IsDebugEnabled())
168+
{
169+
Debug.Log($"<b><color=#2EA3FF>MCP-TELEMETRY</color></b>: {telemetryData["event_type"]}");
170+
}
171+
172+
// TODO: Integrate with MCPForUnityBridge command system
173+
// We would send this as a special telemetry command to the Python server
174+
}
175+
176+
private static bool IsDebugEnabled()
177+
{
178+
try
179+
{
180+
return UnityEditor.EditorPrefs.GetBool("MCPForUnity.DebugLogs", false);
181+
}
182+
catch
183+
{
184+
return false;
185+
}
186+
}
187+
}
188+
}

0 commit comments

Comments
 (0)