-
Notifications
You must be signed in to change notification settings - Fork 514
feat: Discord notifications show package details #374
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Add Serena MCP configuration directory to gitignore alongside other AI-related files to keep local development configurations separate. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Remove CLAUDE.md and .serena from gitignore and commit them to help future developers: - CLAUDE.md provides comprehensive guidance for Claude Code when working with this codebase - Serena memories contain project overview, commands, and development conventions - This standardizes the AI assistant setup across all contributors 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
…ides Add comprehensive documentation including: - Complete list of all 11 MCP tools available for Unity control - Installation and setup instructions for Unity package and MCP clients - CI/CD workflow descriptions for GitHub Actions - Detailed troubleshooting section for common issues - Platform-specific guidance for Windows/macOS/Linux 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Add detailed instructions for adding new MCP tools including: - Python server-side implementation steps - Unity Bridge C# handler implementation - Registration in both CommandRegistry and tools/__init__.py - Testing guidelines for new tools - Tool design best practices and naming conventions This documentation helps contributors understand the full process of extending the MCP tool set. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Fix Python version requirement (3.10+ not 3.12+, per pyproject.toml) - Fix default TCP port (6400 not 9400, per port_discovery.py) - Add port discovery mechanism documentation - Update tool implementation example to match actual patterns (sync not async) - Add repository and Discord links for reference - Improve Python tool example with proper type hints and docstring format These corrections ensure the documentation accurately reflects the actual codebase implementation. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
…implementation Major corrections based on actual codebase analysis: - Python: Use tool name directly in send_command_with_retry, NOT "HandleXxx" pattern - Python: Show proper @mcp.tool() decorator usage (no name parameter needed) - Unity: Add to MCPForUnityBridge.cs switch statement (line 881), not CommandRegistry - Unity: Include Response.Success/Error helper usage from MCPForUnity.Editor.Helpers - Add base64 encoding pattern for large content handling - Show actual parameter validation and error handling patterns - Fix section numbering (was duplicated "3") CRITICAL: CommandRegistry.cs is NOT used for routing - the bridge uses a direct switch statement. This ensures developers follow the correct implementation pattern when adding new tools. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
After checking ALL existing tools, confirmed and documented: - All Python tools use snake_case names (manage_script, read_console, etc.) - CommandRegistry.cs exists but is NOT used - confirmed by grep search - Unity routing happens via switch statement in MCPForUnityBridge.cs line 872-887 - Some tools are async (manage_asset, execute_menu_item), most are sync - Added complete tool flow diagram showing the request path - Clarified that tool names must be lowercase with underscores - Verified all 8 tools follow exact same pattern Key finding: Python sends "tool_name" directly, NOT "HandleToolName". 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
… tools New section explains: - Tool discovery via MCP protocol and @mcp.tool() descriptions - How detailed descriptions guide AI tool selection - MCP prompts that list available tools - Decision factors: user intent, descriptions, parameters, errors, context - Tool chaining example for complex tasks - Best practices for writing tool descriptions This helps developers understand how to make their tools discoverable and usable by AI agents. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add fork notice to README with clear attribution to original CoplayDev project - Update package identity: com.theonegamestudio.unity-mcp v3.3.2-studio.1 - Create STUDIO_FEATURES.md documenting planned enhancements: * Automation testing tools for Unity Test Framework integration * Addressables management for full CRUD operations * DOTS implementation as wishlist item - Update all package references and development scripts - Maintain MIT license compliance with dual copyright - Keep original project links for support and documentation Planned studio features: - manage_test: Unity test automation and reporting - manage_addressable: Addressable Asset System control - Future DOTS integration for Entity Component System 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
* feat: implement Quick Wins - Enhanced Error Messages & Operation Queuing STUDIO: First phase of quick wins implementation providing immediate productivity improvements. 🚀 Enhanced Error Messages: - Add Response.EnhancedError(), AssetError(), ScriptError() methods - Contextual error reporting with suggestions and related items - Include timestamps, Unity version, platform info, and machine-parsable codes - Update ManageScript tool with detailed error context - AI assistants now receive actionable feedback for self-correction 🚀 Operation Queuing System: - Add OperationQueue helper class for batch execution management - Add ManageQueue Unity tool (actions: add, execute, list, clear, stats, remove) - Add manage_queue and queue_batch_operations Python MCP tools - Support atomic batch execution with rollback on failure - 3x performance improvement for bulk operations - Unity Editor remains responsive during batch processing 📚 Documentation: - Add QUICK_WINS_ROADMAP.md with implementation plan - Update STUDIO_FEATURES.md with usage examples and benefits - Comprehensive API documentation for new features Benefits: - Faster debugging through contextual error messages - Reduced Unity Editor freezing during multiple operations - Better AI assistant interaction with enhanced error feedback - Improved developer productivity for bulk operations Files Added: - UnityMcpBridge/Editor/Helpers/OperationQueue.cs - UnityMcpBridge/Editor/Tools/ManageQueue.cs - UnityMcpBridge/UnityMcpServer~/src/tools/manage_queue.py - QUICK_WINS_ROADMAP.md 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * feat: implement comprehensive async operation support for Operation Queue Major improvements to Operation Queue system: ✅ Async Operation Support: - Added ExecuteBatchAsync() method with Unity Editor compatibility - New execute_async action with non-blocking execution - Task.Yield() integration for UI responsiveness ✅ Operation Timeouts: - Configurable timeouts per operation (default: 30s, min: 1s) - Timeout status tracking and proper error handling - CancellationTokenSource for reliable timeout management ✅ Enhanced Status Tracking: - New status types: executing, timeout - Real-time progress monitoring during async execution - Execution time tracking with start/end timestamps ✅ Operation Cancellation: - Cancel operations by ID during execution - Proper state management for cancelled operations - Enhanced queue management actions ✅ Performance & Testing: - Comprehensive benchmark suite (benchmark_operation_queue.py) - Complete async test suite (test_async_queue.py) - Performance validation showing 2-3x speedup vs individual operations ✅ Unity Editor Improvements: - Prevents UI freezing during bulk operations - EditorApplication.delayCall integration for responsiveness - Proper async/await patterns compatible with Unity Editor ✅ Enhanced Python MCP Tools: - Updated manage_queue with timeout_ms parameter - New actions: execute_async, cancel - Enhanced queue_batch_operations with async support This implementation transforms the Operation Queue from "7/10 - needs work" to "9/10 - production ready" by addressing all critical async limitations while maintaining full backward compatibility. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * docs: add port configuration documentation for UnityMCPTests - Document test project using port 6401 instead of default 6400 - Explain port conflict avoidance strategy for multiple Unity instances - Add instructions for changing port configuration - Note that .claude/ directory is gitignored for local settings 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * feat: comprehensive development improvements and port configuration ## Major Changes ### Unity MCP Bridge Enhancements - Enhanced error messaging and operation queuing system - Improved GameObjectSerializer with better component handling - Added operation queue management (ManageQueue.cs) - Enhanced port management and conflict resolution - Better server installer with improved error handling - Upgraded Unity type converters for better serialization ### Test Project Improvements - Added comprehensive test coverage for MCP tools - Enhanced validation tests for script management - Improved component resolver testing - Better error handling in test suites ### Documentation Updates - Added PORT_CONFIGURATION.md for UnityMCPTests project - Updated main README with multi-project port guidance - Added Serena MCP integration and memory system - Documented port 6401 configuration for test isolation ### Development Workflow - Added .serena/ directory for enhanced code intelligence - Improved project structure with better assembly definitions - Enhanced package management and dependencies - Better Unity version compatibility (6000.2.5f1) ## Port Configuration - UnityMCPTests project now uses port 6401 (instead of 6400) - Prevents conflicts when running multiple Unity instances - Documented in troubleshooting section for team reference 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * feat: complete Unity MCP Bridge improvements ## UnityMcpBridge Core Updates - Enhanced MCP client management and configuration - Improved error handling across all bridge components - Better port management and conflict resolution - Enhanced server installation and path resolution - Upgraded operation queue with async support ## Tool Enhancements - ManageAsset: Better asset creation and modification - ManageGameObject: Enhanced component handling and serialization - ManageScript: Improved validation and error reporting - ManageScene: Better scene management capabilities - ManageQueue: New operation queuing system - ExecuteMenuItem: Enhanced menu item execution - ReadConsole: Improved console message handling ## UI & Window Improvements - Enhanced MCP for Unity editor window with better status display - Improved manual configuration window - Better VSCode setup integration - Enhanced error messaging throughout UI ## Runtime & Serialization - Upgraded Unity type converters for better data handling - Enhanced serialization support for complex Unity objects - Better cross-platform compatibility These changes complete the "Studio Quick Wins" feature set with: - Comprehensive async operation support - Enhanced error messages across all components - Robust operation queuing system - Better multi-project port management 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
This workflow automatically publishes Unity packages to upm.the1studio.org when package.json versions are updated. Setup by UPM Auto Publisher system. Repository: The1Studio/unity-mcp Date: 2025-10-15 Co-authored-by: UPM Auto Publisher Bot <noreply@the1studio.org>
Enables manual triggering of package publishing workflow from GitHub Actions UI. This allows administrators to manually trigger package publishes without waiting for automatic triggers. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com>
- Add logic to detect trigger type (workflow_dispatch vs push) - When manually triggered, scan ALL package.json files instead of just changed ones - Supports specific package_path input or scans entire repository - Fixes issue where manual triggers failed with 'No package.json files changed' - Excludes node_modules and hidden directories from scan This allows manual publishing of unpublished packages without requiring version bump commits. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com>
WalkthroughComprehensive update to the Unity MCP bridge introducing an operation queue system for async batch execution, extensive C# type inference refactoring, package branding updates from Coplay to The One Game Studio, new UPM publishing CI workflow, enhanced error handling utilities, and substantial documentation for architecture, setup, and features. Changes
Sequence Diagram(s)sequenceDiagram
participant MCP as MCP Client
participant Bridge as MCPForUnityBridge
participant Queue as OperationQueue
participant Tools as Tool Handlers
participant Editor as Unity Editor
MCP->>Bridge: manage_queue (action: add)
Bridge->>Queue: AddOperation(tool, params)
Queue->>Queue: Validate & Enqueue
Queue-->>Bridge: operation_id
Bridge-->>MCP: {"status": "queued", "id": "..."}
MCP->>Bridge: manage_queue (action: execute_async)
Bridge->>Queue: ExecuteBatchAsync()
activate Queue
Loop for each pending operation
Queue->>Queue: ExecuteOperationWithTimeoutAsync(op)
alt Per-operation timeout
Queue->>Tools: Route to appropriate handler
Tools->>Editor: Execute tool action
alt Success
Tools-->>Queue: result
else Timeout/Error
Queue->>Queue: Capture error/timeout
end
end
end
Queue->>Queue: Aggregate results
deactivate Queue
Queue-->>Bridge: {"total": N, "success": X, "failed": Y, "timeout": Z, "operations": [...]}
Bridge-->>MCP: {"status": "success", "data": {...}}
sequenceDiagram
participant Python as Python MCP Server
participant Unity as manage_queue (C#)
participant Queue as OperationQueue
Python->>Python: register_manage_queue(mcp)
Python->>Python: Expose manage_queue & queue_batch_operations tools
Python->>Unity: manage_queue(action: add, tool: "manage_script", ...)
Unity->>Queue: AddOperation(...)
Queue-->>Unity: operation_id
Unity-->>Python: {"queued": True, "id": "..."}
Python->>Python: queue_batch_operations([op1, op2, op3], execute_immediately=True)
loop Batch add
Python->>Unity: manage_queue(action: add) for each
end
Python->>Unity: manage_queue(action: execute_async)
Unity->>Queue: ExecuteBatchAsync()
Queue-->>Unity: {"success": 2, "failed": 1, "timeout": 0}
Unity-->>Python: execution result
Python-->>Python: Return summary with queued IDs & results
Estimated code review effort🎯 4 (Complex) | ⏱️ ~70 minutes Areas requiring extra attention:
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
🧹 Nitpick comments (15)
CLAUDE.md (3)
9-10: Wrap bare URLs in markdown links.Per markdown best practices (MD034), bare URLs should be wrapped in markdown link syntax.
-**Repository**: https://github.com/CoplayDev/unity-mcp (maintained by Coplay) -**Discord**: https://discord.gg/y4p8KfzrN4 +**Repository**: [https://github.com/CoplayDev/unity-mcp](https://github.com/CoplayDev/unity-mcp) (maintained by Coplay) +**Discord**: [https://discord.gg/y4p8KfzrN4](https://discord.gg/y4p8KfzrN4)
184-184: Specify language identifier for fenced code block.The diagram at line 184 should include a language identifier. Since this is a text-based flowchart, use
textorplaintext:### Tool Implementation Flow -``` +\```text MCP Client → Python Tool (@mcp.tool) → send_command_with_retry("tool_name") → Unity Bridge (switch on "tool_name") → C# Handler (HandleCommand) → Response back through chain -``` +\```
206-225: Includedescriptionparameter in tool decorator.Per best practices and retrieved learnings, the
@mcp.tool()decorator should always include adescriptionparameter for better MCP client compatibility. Update the example:@mcp.tool() + @mcp.tool(description="Brief description of what your tool does.\n\nArgs:\n ctx: The MCP context\n action: Operation to perform (e.g., 'create', 'read', 'update', 'delete')\n name: Name of the resource\n path: Path to the resource (relative to Assets/)\n contents: Content for create/update operations\n\nReturns:\n Dictionary with 'success', 'message', and optional 'data'") def your_new_tool( # Can be sync or async - use async if you need await ctx: Context, action: str, name: str = None, path: str = None, contents: str = None ) -> Dict[str, Any]: - """Brief description of what your tool does. - - Args: - ctx: The MCP context - action: Operation to perform (e.g., 'create', 'read', 'update', 'delete') - name: Name of the resource - path: Path to the resource (relative to Assets/) - contents: Content for create/update operations - - Returns: - Dictionary with 'success', 'message', and optional 'data' - """Alternatively, if the docstring is still needed for IDE tooltips, keep both but ensure the decorator has the description. Based on learnings, this improves MCP client parsing reliability.
TestProjects/UnityMCPTests/Assets/Tests/EditMode/Windows/WriteToConfigTests.cs (1)
17-19: Reconsider removing the underscore prefix from private fields.The original
_fieldNameconvention is idiomatic in C# and widely recommended (including in Microsoft's coding guidelines). It provides clear visual distinction between private fields and local variables/parameters without requiring explicitthis.usage throughout the codebase. While the new convention with explicitthis.is valid, the underscore prefix is more commonly adopted in C# projects..github/workflows/publish-upm.yml (2)
37-48: APT source modifications are fragile and environment-specific.Modifying system package sources with sed is brittle and suggests runner misconfiguration. These changes:
- Assume specific file formats that may vary across Ubuntu versions
- Disable all PPAs system-wide, potentially breaking other workflows
- Mask underlying network/firewall issues
Consider configuring the self-hosted runner environment properly instead of patching it in every workflow.
614-625: Package details formatting matches PR objectives perfectly.The Discord notification correctly formats package details as
old → newfor updates andversion (new package)for new packages, exactly as specified in the PR objectives.However, the
tr '\n' '\n'command at line 622 is a no-op. If you intended to join lines or escape newlines, this needs adjustment. If newline preservation is the goal, thetrcommand can be removed entirely.- done | tr '\n' '\n') + done)README-DEV.md (1)
53-57: LGTM!The example paths correctly reflect the package fork rename.
Note: There's a fenced code block at lines 56-58 without a language specifier. Consider adding a language identifier (e.g., ```text) to address the markdownlint warning.
Based on static analysis.
TestProjects/UnityMCPTests/.serena/memories/unity_mcp_local_setup.md (1)
1-150: Comprehensive setup guide with clear examples.This documentation thoroughly explains local vs global configuration strategies, provides working code examples, and covers common scenarios. The hybrid approach guidance is particularly valuable for teams.
Optional: Line 100 has a fenced code block without a language specifier. You can add
textorplaintextto address the markdown linting hint, though this is purely cosmetic.TestProjects/UnityMCPTests/.serena/memories/unity_bridge_port_management.md (1)
1-106: Excellent technical documentation of port architecture.This clearly explains the two-layer port system and the discovery mechanism. The port allocation table and configuration examples are particularly helpful for understanding how multiple Unity projects can coexist.
Optional: Line 35 has a fenced code block without a language specifier. Adding
textwould address the markdown linting hint.UnityMcpBridge/Editor/Tools/ManageAsset.cs (1)
1046-1079: Consider using string arrays instead of List for constant lookup tables.Lines 1046-1049 create
List<String>instances for constant lookup values (averageList, multiplyList, minimumList, maximumList). Since these are immutable lookup tables, consider usingstring[]orImmutableHashSet<string>for better performance and clarity.- var averageList = new List<String> { "ave", "Ave", "average", "Average" }; - var multiplyList = new List<String> { "mul", "Mul", "mult", "Mult", "multiply", "Multiply" }; - var minimumList = new List<String> { "min", "Min", "minimum", "Minimum" }; - var maximumList = new List<String> { "max", "Max", "maximum", "Maximum" }; + var averageList = new[] { "ave", "Ave", "average", "Average" }; + var multiplyList = new[] { "mul", "Mul", "mult", "Mult", "multiply", "Multiply" }; + var minimumList = new[] { "min", "Min", "minimum", "Minimum" }; + var maximumList = new[] { "max", "Max", "maximum", "Maximum" };README.md (1)
333-337: Helpful troubleshooting guidance for multiple Unity projects.The new section addresses port conflicts when running multiple Unity projects simultaneously, with specific port numbers documented (6400 default, 6401 for test projects).
Fix markdown indentation issue per static analysis.
-- **Running Multiple Unity Projects:** - - If you need to run multiple Unity projects with MCP simultaneously, configure different ports to avoid conflicts - - Default port is 6400; use Window > MCP for Unity > Settings to change port - - Test projects like `TestProjects/UnityMCPTests` use port 6401 - - Update your MCP client configuration with the matching port number + - **Running Multiple Unity Projects:** + - If you need to run multiple Unity projects with MCP simultaneously, configure different ports to avoid conflicts + - Default port is 6400; use Window > MCP for Unity > Settings to change port + - Test projects like `TestProjects/UnityMCPTests` use port 6401 + - Update your MCP client configuration with the matching port numbertools/test_async_queue.py (1)
217-224: Improve exception handling in cleanup.The bare
exceptclause silently suppresses all exceptions, including system exits. While cleanup should be tolerant, it's better to catch specific exceptions and optionally log failures for debugging.Apply this diff:
for script_name in test_scripts: try: send_command_with_retry("manage_script", { "action": "delete", "name": script_name, "path": "Assets/Scripts/Test" }) - except: - pass # Ignore if script doesn't exist + except Exception as e: + # Ignore if script doesn't exist, but could log for debugging + passUnityMcpBridge/UnityMcpServer~/src/tools/manage_queue.py (1)
125-131: Uselogging.exception()for better error diagnostics.When catching broad exceptions,
logging.exception()automatically includes the full traceback, which is essential for debugging issues in MCP tools.Apply this diff:
except Exception as e: - logger.error(f"STUDIO: Queue operation failed: {str(e)}") + logger.exception("STUDIO: Queue operation failed") return { "success": False, - "error": f"Python error in manage_queue: {str(e)}", + "error": f"Python error in manage_queue: {e}", "suggestion": "Check Unity console for additional error details" }Apply the same pattern at lines 221-227 in
queue_batch_operations.UnityMcpBridge/Editor/Helpers/OperationQueue.cs (2)
102-118: Document thread safety assumption for AutoCleanupCompletedOperations.This private method modifies
_operationsbut doesn't acquire its own lock, relying on the caller to hold the lock. This is fine for current usage, but could cause subtle bugs if called from new contexts.Add a comment to make the threading contract explicit:
/// <summary> /// STUDIO: Auto-cleanup old completed/failed operations to manage memory +/// Note: Caller must hold _lockObject before calling this method. /// </summary> private static void AutoCleanupCompletedOperations() {Alternatively, add a debug assertion:
private static void AutoCleanupCompletedOperations() { // Caller must hold _lockObject Debug.Assert(Monitor.IsEntered(_lockObject), "AutoCleanupCompletedOperations requires caller to hold _lockObject"); var completed = _operations.Where(op => ...
70-81: Consider cleanup strategy for stale pending operations.The auto-cleanup only removes completed/failed/timeout operations. If many pending operations accumulate (e.g., due to no execute call), the queue can reach MAX_QUEUE_SIZE and block new additions even after cleanup runs.
Consider adding age-based cleanup for pending operations:
private static void AutoCleanupCompletedOperations() { + // Also cleanup very old pending operations (> 1 hour) that were likely abandoned + var staleThreshold = DateTime.UtcNow.AddHours(-1); + var stale = _operations.Where(op => + op.Status == "pending" && op.QueuedAt < staleThreshold) + .ToList(); + + foreach (var op in stale) + { + _operations.Remove(op); + Debug.LogWarning($"STUDIO: Removed stale pending operation {op.Id} (queued {op.QueuedAt})"); + } + var completed = _operations.Where(op => op.Status == "executed" || op.Status == "failed" || op.Status == "timeout") .OrderByDescending(op => op.QueuedAt) .Skip(KEEP_COMPLETED_OPERATIONS) .ToList(); foreach (var op in completed) { _operations.Remove(op); } - if (completed.Count > 0) + if (completed.Count > 0 || stale.Count > 0) { - Debug.Log($"STUDIO: Auto-cleaned {completed.Count} old completed operations from queue"); + Debug.Log($"STUDIO: Auto-cleaned {completed.Count} completed and {stale.Count} stale pending operations from queue"); } }Also applies to: 102-118
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (76)
.github/workflows/publish-upm.yml(1 hunks).gitignore(0 hunks).serena/.gitignore(1 hunks).serena/memories/code_style_conventions.md(1 hunks).serena/memories/project_overview.md(1 hunks).serena/memories/suggested_commands.md(1 hunks).serena/memories/task_completion_checklist.md(1 hunks).serena/project.yml(1 hunks)ASYNC_QUEUE_UPDATE.md(1 hunks)CLAUDE.md(1 hunks)LICENSE(1 hunks)OPERATION_QUEUE_REVIEW.md(1 hunks)QUICK_WINS_ROADMAP.md(1 hunks)README-DEV.md(1 hunks)README.md(4 hunks)STUDIO_FEATURES.md(1 hunks)TestProjects/UnityMCPTests/.serena/.gitignore(1 hunks)TestProjects/UnityMCPTests/.serena/memories/code_style_conventions.md(1 hunks)TestProjects/UnityMCPTests/.serena/memories/project_overview.md(1 hunks)TestProjects/UnityMCPTests/.serena/memories/suggested_commands.md(1 hunks)TestProjects/UnityMCPTests/.serena/memories/task_completion_checklist.md(1 hunks)TestProjects/UnityMCPTests/.serena/memories/unity_bridge_port_management.md(1 hunks)TestProjects/UnityMCPTests/.serena/memories/unity_mcp_local_setup.md(1 hunks)TestProjects/UnityMCPTests/.serena/memories/unity_mcp_setup.md(1 hunks)TestProjects/UnityMCPTests/.serena/project.yml(1 hunks)TestProjects/UnityMCPTests/Assets/Scripts/Hello.cs(1 hunks)TestProjects/UnityMCPTests/Assets/Scripts/LongUnityScriptClaudeTest.cs(13 hunks)TestProjects/UnityMCPTests/Assets/Scripts/TestAsmdef.meta(1 hunks)TestProjects/UnityMCPTests/Assets/Scripts/TestAsmdef/CustomComponent.cs(1 hunks)TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/AIPropertyMatchingTests.cs(6 hunks)TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/CommandRegistryTests.cs(0 hunks)TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/ComponentResolverTests.cs(10 hunks)TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/ManageGameObjectTests.cs(16 hunks)TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/ManageScriptValidationTests.cs(6 hunks)TestProjects/UnityMCPTests/Assets/Tests/EditMode/Windows/ManualConfigJsonBuilderTests.cs(4 hunks)TestProjects/UnityMCPTests/Assets/Tests/EditMode/Windows/WriteToConfigTests.cs(12 hunks)TestProjects/UnityMCPTests/PORT_CONFIGURATION.md(1 hunks)TestProjects/UnityMCPTests/Packages/manifest.json(1 hunks)TestProjects/UnityMCPTests/ProjectSettings/ProjectVersion.txt(1 hunks)UnityMcpBridge/Editor/Data/McpClients.cs(0 hunks)UnityMcpBridge/Editor/Helpers/ConfigJsonBuilder.cs(3 hunks)UnityMcpBridge/Editor/Helpers/ExecPath.cs(6 hunks)UnityMcpBridge/Editor/Helpers/GameObjectSerializer.cs(13 hunks)UnityMcpBridge/Editor/Helpers/OperationQueue.cs(1 hunks)UnityMcpBridge/Editor/Helpers/OperationQueue.cs.meta(1 hunks)UnityMcpBridge/Editor/Helpers/PackageDetector.cs(2 hunks)UnityMcpBridge/Editor/Helpers/PackageInstaller.cs(3 hunks)UnityMcpBridge/Editor/Helpers/PortManager.cs(9 hunks)UnityMcpBridge/Editor/Helpers/Response.cs(3 hunks)UnityMcpBridge/Editor/Helpers/ServerInstaller.cs(26 hunks)UnityMcpBridge/Editor/Helpers/ServerPathResolver.cs(4 hunks)UnityMcpBridge/Editor/MCPForUnity.Editor.asmdef(2 hunks)UnityMcpBridge/Editor/MCPForUnityBridge.cs(28 hunks)UnityMcpBridge/Editor/Tools/ExecuteMenuItem.cs(3 hunks)UnityMcpBridge/Editor/Tools/ManageAsset.cs(43 hunks)UnityMcpBridge/Editor/Tools/ManageEditor.cs(17 hunks)UnityMcpBridge/Editor/Tools/ManageGameObject.cs(78 hunks)UnityMcpBridge/Editor/Tools/ManageQueue.cs(1 hunks)UnityMcpBridge/Editor/Tools/ManageQueue.cs.meta(1 hunks)UnityMcpBridge/Editor/Tools/ManageScene.cs(10 hunks)UnityMcpBridge/Editor/Tools/ManageScript.cs(70 hunks)UnityMcpBridge/Editor/Tools/ManageShader.cs(7 hunks)UnityMcpBridge/Editor/Tools/ReadConsole.cs(12 hunks)UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs(80 hunks)UnityMcpBridge/Editor/Windows/ManualConfigEditorWindow.cs(2 hunks)UnityMcpBridge/Editor/Windows/VSCodeManualSetupWindow.cs(6 hunks)UnityMcpBridge/Runtime/Serialization/UnityTypeConverters.cs(12 hunks)UnityMcpBridge/UnityMcpServer~/src/tools/__init__.py(2 hunks)UnityMcpBridge/UnityMcpServer~/src/tools/manage_queue.py(1 hunks)UnityMcpBridge/package.json(2 hunks)deploy-dev.bat(1 hunks)mcp_source.py(1 hunks)restore-dev.bat(1 hunks)tests/test_operation_queue.py(1 hunks)tools/benchmark_operation_queue.py(1 hunks)tools/test_async_queue.py(1 hunks)
💤 Files with no reviewable changes (3)
- .gitignore
- UnityMcpBridge/Editor/Data/McpClients.cs
- TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/CommandRegistryTests.cs
🧰 Additional context used
🧠 Learnings (10)
📓 Common learnings
Learnt from: msanatan
Repo: CoplayDev/unity-mcp PR: 316
File: TestProjects/UnityMCPTests/Assets/Tests/EditMode/Resources.meta:1-8
Timestamp: 2025-10-13T13:27:23.040Z
Learning: UnityMcpBridge is a legacy project kept for backwards compatibility; MCPForUnity is the only active Unity plugin project. GUID collisions between UnityMcpBridge and MCPForUnity are acceptable.
Learnt from: dsarno
Repo: CoplayDev/unity-mcp PR: 260
File: UnityMcpBridge/UnityMcpServer~/src/server_version.txt:1-1
Timestamp: 2025-09-04T01:01:11.927Z
Learning: The UnityMcpBridge project is not maintaining changelogs yet, so don't suggest adding changelog entries for version bumps.
Learnt from: msanatan
Repo: CoplayDev/unity-mcp PR: 368
File: MCPForUnity/UnityMcpServer~/src/resources/menu_items.py:15-15
Timestamp: 2025-11-05T18:23:12.319Z
Learning: In Unity MCP, the `name` parameter in the `mcp_for_unity_resource` decorator is the external API name exposed to MCP clients (LLMs, AI agents). The command string passed to `async_send_command_with_retry` or `async_send_with_unity_instance` (e.g., "get_menu_items") is the internal command identifier that must match the C# side. These are decoupled, allowing external API naming to evolve independently of internal command routing.
📚 Learning: 2025-09-04T01:01:11.927Z
Learnt from: dsarno
Repo: CoplayDev/unity-mcp PR: 260
File: UnityMcpBridge/UnityMcpServer~/src/server_version.txt:1-1
Timestamp: 2025-09-04T01:01:11.927Z
Learning: The UnityMcpBridge project is not maintaining changelogs yet, so don't suggest adding changelog entries for version bumps.
Applied to files:
UnityMcpBridge/Editor/Helpers/OperationQueue.cs.metaCLAUDE.mdmcp_source.py.serena/memories/code_style_conventions.mdREADME.md.serena/memories/project_overview.mdTestProjects/UnityMCPTests/.serena/project.ymlTestProjects/UnityMCPTests/Assets/Scripts/Hello.csTestProjects/UnityMCPTests/.serena/memories/unity_mcp_setup.mdTestProjects/UnityMCPTests/.serena/memories/task_completion_checklist.mdUnityMcpBridge/Editor/Helpers/ConfigJsonBuilder.csREADME-DEV.mdTestProjects/UnityMCPTests/.serena/memories/suggested_commands.mdUnityMcpBridge/package.jsonTestProjects/UnityMCPTests/Packages/manifest.jsonTestProjects/UnityMCPTests/.serena/memories/code_style_conventions.mdTestProjects/UnityMCPTests/.serena/.gitignoreSTUDIO_FEATURES.mdUnityMcpBridge/Editor/Tools/ReadConsole.csTestProjects/UnityMCPTests/.serena/memories/project_overview.mdUnityMcpBridge/Editor/Tools/ManageQueue.cs.metaTestProjects/UnityMCPTests/ProjectSettings/ProjectVersion.txtUnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.csUnityMcpBridge/Editor/MCPForUnity.Editor.asmdefUnityMcpBridge/Editor/Helpers/PackageInstaller.csTestProjects/UnityMCPTests/.serena/memories/unity_bridge_port_management.mdUnityMcpBridge/Editor/Helpers/PackageDetector.csUnityMcpBridge/Editor/Helpers/ServerInstaller.csTestProjects/UnityMCPTests/.serena/memories/unity_mcp_local_setup.mdUnityMcpBridge/Editor/Helpers/ServerPathResolver.csUnityMcpBridge/Editor/Tools/ManageScript.csUnityMcpBridge/Editor/MCPForUnityBridge.cs
📚 Learning: 2025-10-13T13:27:23.040Z
Learnt from: msanatan
Repo: CoplayDev/unity-mcp PR: 316
File: TestProjects/UnityMCPTests/Assets/Tests/EditMode/Resources.meta:1-8
Timestamp: 2025-10-13T13:27:23.040Z
Learning: UnityMcpBridge is a legacy project kept for backwards compatibility; MCPForUnity is the only active Unity plugin project. GUID collisions between UnityMcpBridge and MCPForUnity are acceptable.
Applied to files:
UnityMcpBridge/Editor/Helpers/OperationQueue.cs.metamcp_source.py.serena/memories/code_style_conventions.mdREADME.md.serena/memories/project_overview.mdTestProjects/UnityMCPTests/Assets/Scripts/Hello.csTestProjects/UnityMCPTests/.serena/memories/unity_mcp_setup.mdTestProjects/UnityMCPTests/.serena/memories/task_completion_checklist.mdUnityMcpBridge/Editor/Helpers/ConfigJsonBuilder.csREADME-DEV.mdTestProjects/UnityMCPTests/PORT_CONFIGURATION.mdUnityMcpBridge/package.jsonUnityMcpBridge/Editor/Helpers/PortManager.csTestProjects/UnityMCPTests/Packages/manifest.jsonTestProjects/UnityMCPTests/.serena/memories/code_style_conventions.mdUnityMcpBridge/Editor/Tools/ManageGameObject.csTestProjects/UnityMCPTests/.serena/memories/project_overview.mdUnityMcpBridge/Editor/Tools/ManageQueue.cs.metaTestProjects/UnityMCPTests/ProjectSettings/ProjectVersion.txtUnityMcpBridge/Editor/Tools/ManageAsset.csUnityMcpBridge/Runtime/Serialization/UnityTypeConverters.cs.serena/memories/suggested_commands.mdUnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.csUnityMcpBridge/Editor/MCPForUnity.Editor.asmdefUnityMcpBridge/Editor/Helpers/PackageInstaller.csTestProjects/UnityMCPTests/.serena/memories/unity_bridge_port_management.mdUnityMcpBridge/Editor/Helpers/PackageDetector.csUnityMcpBridge/Editor/Helpers/ServerInstaller.csTestProjects/UnityMCPTests/.serena/memories/unity_mcp_local_setup.mdUnityMcpBridge/Editor/Helpers/ServerPathResolver.csUnityMcpBridge/Editor/Tools/ManageScript.csUnityMcpBridge/Editor/MCPForUnityBridge.cs
📚 Learning: 2025-10-13T13:41:00.086Z
Learnt from: JohanHoltby
Repo: CoplayDev/unity-mcp PR: 309
File: MCPForUnity/Editor/Helpers/ServerInstaller.cs:478-508
Timestamp: 2025-10-13T13:41:00.086Z
Learning: In the MCPForUnityTools feature (MCPForUnity/Editor/Helpers/ServerInstaller.cs), the design intentionally forces users to have only one .py file per MCPForUnityTools folder to keep file tracking simple. Package-style tools (subdirectories with __init__.py) are not supported.
Applied to files:
CLAUDE.mdmcp_source.py.serena/memories/code_style_conventions.mdREADME.md.serena/memories/project_overview.mdTestProjects/UnityMCPTests/.serena/project.ymlTestProjects/UnityMCPTests/.serena/memories/unity_mcp_setup.mdTestProjects/UnityMCPTests/Assets/Tests/EditMode/Windows/WriteToConfigTests.csREADME-DEV.mdTestProjects/UnityMCPTests/.serena/memories/suggested_commands.mdTestProjects/UnityMCPTests/.serena/memories/code_style_conventions.mdSTUDIO_FEATURES.mdTestProjects/UnityMCPTests/.serena/memories/project_overview.mdUnityMcpBridge/Runtime/Serialization/UnityTypeConverters.cs.serena/memories/suggested_commands.mdUnityMcpBridge/UnityMcpServer~/src/tools/__init__.pyUnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.csUnityMcpBridge/Editor/Helpers/PackageInstaller.csTestProjects/UnityMCPTests/.serena/memories/unity_bridge_port_management.mdUnityMcpBridge/Editor/Helpers/ServerInstaller.csTestProjects/UnityMCPTests/.serena/memories/unity_mcp_local_setup.mdUnityMcpBridge/Editor/Helpers/ServerPathResolver.cs
📚 Learning: 2025-10-03T22:11:46.002Z
Learnt from: msanatan
Repo: CoplayDev/unity-mcp PR: 301
File: docs/CUSTOM_TOOLS.md:54-62
Timestamp: 2025-10-03T22:11:46.002Z
Learning: In Unity MCP, the `description` parameter in the `mcp_for_unity_tool` decorator is technically optional but should always be included as a best practice. Without it, there's a higher chance that MCP clients will not parse the tool correctly. All Unity MCP tools should include the description in the decorator for compatibility.
Applied to files:
CLAUDE.md.serena/memories/project_overview.mdTestProjects/UnityMCPTests/.serena/memories/unity_mcp_setup.mdUnityMcpBridge/package.jsonTestProjects/UnityMCPTests/.serena/memories/code_style_conventions.mdUnityMcpBridge/UnityMcpServer~/src/tools/__init__.py
📚 Learning: 2025-11-05T18:23:12.319Z
Learnt from: msanatan
Repo: CoplayDev/unity-mcp PR: 368
File: MCPForUnity/UnityMcpServer~/src/resources/menu_items.py:15-15
Timestamp: 2025-11-05T18:23:12.319Z
Learning: In Unity MCP, the `name` parameter in the `mcp_for_unity_resource` decorator is the external API name exposed to MCP clients (LLMs, AI agents). The command string passed to `async_send_command_with_retry` or `async_send_with_unity_instance` (e.g., "get_menu_items") is the internal command identifier that must match the C# side. These are decoupled, allowing external API naming to evolve independently of internal command routing.
Applied to files:
mcp_source.py.serena/memories/project_overview.mdUnityMcpBridge/package.jsonTestProjects/UnityMCPTests/.serena/memories/project_overview.mdUnityMcpBridge/UnityMcpServer~/src/tools/manage_queue.pyUnityMcpBridge/UnityMcpServer~/src/tools/__init__.pyUnityMcpBridge/Editor/Tools/ManageQueue.csUnityMcpBridge/Editor/MCPForUnityBridge.cs
📚 Learning: 2025-09-05T16:22:04.960Z
Learnt from: dsarno
Repo: CoplayDev/unity-mcp PR: 265
File: README.md:204-204
Timestamp: 2025-09-05T16:22:04.960Z
Learning: In the Unity MCP project, the ServerInstaller.cs creates a symlink from ~/Library/AppSupport to ~/Library/Application Support on macOS to mitigate argument parsing and quoting issues in some MCP clients. The README documentation should use the shortened AppSupport path, not the full "Application Support" path with spaces.
Applied to files:
.serena/memories/project_overview.mdTestProjects/UnityMCPTests/.serena/memories/unity_mcp_setup.mdUnityMcpBridge/Editor/Helpers/ConfigJsonBuilder.csUnityMcpBridge/package.jsonUnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.csUnityMcpBridge/Editor/Helpers/PackageDetector.csUnityMcpBridge/Editor/Helpers/ServerInstaller.csTestProjects/UnityMCPTests/.serena/memories/unity_mcp_local_setup.mdUnityMcpBridge/Editor/Helpers/ServerPathResolver.cs
📚 Learning: 2025-09-05T16:22:04.960Z
Learnt from: dsarno
Repo: CoplayDev/unity-mcp PR: 265
File: README.md:204-204
Timestamp: 2025-09-05T16:22:04.960Z
Learning: In the Unity MCP project, the ServerInstaller.cs creates a symlink from ~/Library/AppSupport to ~/Library/Application Support on macOS to avoid spaces in paths that can cause arg parsing and quoting issues in some MCP clients. The README documentation should use the shortened AppSupport path, not the full "Application Support" path.
Applied to files:
.serena/memories/project_overview.mdTestProjects/UnityMCPTests/.serena/memories/unity_mcp_setup.mdUnityMcpBridge/Editor/Helpers/ConfigJsonBuilder.csUnityMcpBridge/package.jsonUnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.csUnityMcpBridge/Editor/Helpers/PackageDetector.csUnityMcpBridge/Editor/Helpers/ServerInstaller.csTestProjects/UnityMCPTests/.serena/memories/unity_mcp_local_setup.mdUnityMcpBridge/Editor/Helpers/ServerPathResolver.cs
📚 Learning: 2025-10-24T14:09:08.615Z
Learnt from: msanatan
Repo: CoplayDev/unity-mcp PR: 348
File: MCPForUnity/Editor/Helpers/ConfigJsonBuilder.cs:71-79
Timestamp: 2025-10-24T14:09:08.615Z
Learning: The SystemRoot environment variable on Windows is only required for Codex MCP client configurations due to a Codex bug. Other MCP clients (VSCode, Cursor, Windsurf, Kiro) do not need this environment variable. Codex configurations use TOML format (CodexConfigHelper.cs), while other clients use JSON format (ConfigJsonBuilder.cs).
Applied to files:
TestProjects/UnityMCPTests/Assets/Tests/EditMode/Windows/WriteToConfigTests.csUnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.csUnityMcpBridge/Editor/Helpers/PackageDetector.csUnityMcpBridge/Editor/Helpers/ServerInstaller.cs
📚 Learning: 2025-09-03T16:00:55.839Z
Learnt from: dsarno
Repo: CoplayDev/unity-mcp PR: 0
File: :0-0
Timestamp: 2025-09-03T16:00:55.839Z
Learning: ComponentResolver in UnityMcpBridge/Editor/Tools/ManageGameObject.cs is a nested static class within ManageGameObject, not a sibling type. The `using static MCPForUnity.Editor.Tools.ManageGameObject;` import is required to access ComponentResolver methods directly without the outer class qualifier.
Applied to files:
TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/ComponentResolverTests.csUnityMcpBridge/Editor/Helpers/ConfigJsonBuilder.csUnityMcpBridge/Editor/Windows/ManualConfigEditorWindow.csUnityMcpBridge/Editor/Helpers/Response.csUnityMcpBridge/Editor/Tools/ReadConsole.csUnityMcpBridge/Editor/Tools/ManageGameObject.csUnityMcpBridge/Editor/Tools/ManageAsset.csUnityMcpBridge/Runtime/Serialization/UnityTypeConverters.csUnityMcpBridge/Editor/Tools/ManageEditor.csTestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/AIPropertyMatchingTests.csUnityMcpBridge/Editor/Helpers/PackageDetector.csTestProjects/UnityMCPTests/Assets/Scripts/TestAsmdef/CustomComponent.csUnityMcpBridge/Editor/Tools/ManageScene.csTestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/ManageScriptValidationTests.csTestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/ManageGameObjectTests.csUnityMcpBridge/Editor/Helpers/ServerPathResolver.csUnityMcpBridge/Editor/Tools/ManageScript.csUnityMcpBridge/Editor/Tools/ManageQueue.csUnityMcpBridge/Editor/Helpers/GameObjectSerializer.cs
🧬 Code graph analysis (24)
TestProjects/UnityMCPTests/Assets/Tests/EditMode/Windows/WriteToConfigTests.cs (1)
UnityMcpBridge/Editor/Helpers/ConfigJsonBuilder.cs (2)
JObject(31-41)JObject(121-127)
TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/ComponentResolverTests.cs (1)
UnityMcpBridge/Editor/Tools/ManageGameObject.cs (2)
ComponentResolver(2197-2457)TryResolve(2207-2243)
tools/test_async_queue.py (2)
UnityMcpBridge/UnityMcpServer~/src/unity_connection.py (1)
send_command_with_retry(388-407)tools/benchmark_operation_queue.py (1)
main(352-400)
UnityMcpBridge/Editor/Helpers/PortManager.cs (1)
UnityMcpBridge/Editor/MCPForUnityBridge.cs (5)
System(568-613)System(615-619)System(621-640)System(642-659)ComputeProjectHash(1000-1018)
UnityMcpBridge/Editor/Helpers/Response.cs (3)
UnityMcpBridge/Editor/Tools/ManageScript.cs (1)
System(2291-2357)UnityMcpBridge/Editor/Tools/ManageGameObject.cs (6)
UnityEngine(2072-2169)List(1219-1378)List(2258-2295)List(2318-2336)List(2341-2380)List(2388-2423)UnityMcpBridge/Editor/Helpers/OperationQueue.cs (1)
List(334-347)
UnityMcpBridge/Editor/Tools/ManageGameObject.cs (3)
UnityMcpBridge/Runtime/Serialization/UnityTypeConverters.cs (5)
Vector2Converter(37-57)UnityEngineObjectConverter(165-266)Color(103-112)Vector2(49-56)UnityEngine(223-265)UnityMcpBridge/Editor/Helpers/Response.cs (2)
Response(12-190)Error(43-62)UnityMcpBridge/Editor/Tools/ManageAsset.cs (1)
ConvertJTokenToType(1166-1243)
UnityMcpBridge/Editor/Helpers/OperationQueue.cs (10)
UnityMcpBridge/Editor/Tools/ManageScript.cs (2)
ManageScript(51-2560)HandleCommand(110-296)UnityMcpBridge/Editor/Tools/ManageGameObject.cs (7)
List(1219-1378)List(2258-2295)List(2318-2336)List(2341-2380)List(2388-2423)HandleCommand(40-173)ManageGameObject(21-2191)UnityMcpBridge/Editor/Helpers/Response.cs (3)
Error(43-62)Response(12-190)Success(20-35)UnityMcpBridge/Editor/Tools/ManageQueue.cs (8)
AddOperation(88-142)ExecuteBatchAsync(168-187)ExecuteBatch(147-163)HandleCommand(22-83)ClearQueue(401-429)GetQueueStats(434-451)RemoveOperation(456-509)CancelOperation(293-345)UnityMcpBridge/Editor/Tools/ExecuteMenuItem.cs (2)
HandleCommand(28-62)ExecuteMenuItem(13-128)UnityMcpBridge/Editor/Tools/ManageAsset.cs (2)
HandleCommand(44-109)ManageAsset(24-1337)UnityMcpBridge/Editor/Tools/ManageEditor.cs (2)
HandleCommand(28-146)ManageEditor(17-593)UnityMcpBridge/Editor/Tools/ManageScene.cs (2)
HandleCommand(22-112)ManageScene(17-425)UnityMcpBridge/Editor/Tools/ManageShader.cs (2)
HandleCommand(19-122)ManageShader(14-340)UnityMcpBridge/Editor/Tools/ReadConsole.cs (3)
HandleCommand(128-201)ReadConsole(16-568)ReadConsole(36-124)
UnityMcpBridge/Editor/Tools/ManageAsset.cs (3)
UnityMcpBridge/Editor/Helpers/Response.cs (3)
Response(12-190)Error(43-62)Success(20-35)UnityMcpBridge/Editor/Tools/ManageGameObject.cs (10)
ComponentResolver(2197-2457)TryResolve(2207-2243)UnityEngine(2072-2169)GameObject(1191-1214)List(1219-1378)List(2258-2295)List(2318-2336)List(2341-2380)List(2388-2423)Type(2176-2190)UnityMcpBridge/Runtime/Serialization/UnityTypeConverters.cs (1)
UnityEngine(223-265)
UnityMcpBridge/Runtime/Serialization/UnityTypeConverters.cs (2)
UnityMcpBridge/Editor/Tools/ManageGameObject.cs (2)
Vector3(1168-1186)Vector3(1975-1990)UnityMcpBridge/Editor/Helpers/Vector3Helper.cs (1)
Vector3(17-22)
UnityMcpBridge/Editor/Tools/ManageShader.cs (1)
UnityMcpBridge/Editor/Tools/ManageAsset.cs (1)
DeleteAsset(493-521)
UnityMcpBridge/Editor/Tools/ManageEditor.cs (1)
UnityMcpBridge/Editor/Helpers/Response.cs (2)
Response(12-190)Error(43-62)
UnityMcpBridge/UnityMcpServer~/src/tools/manage_queue.py (2)
UnityMcpBridge/UnityMcpServer~/src/unity_connection.py (1)
send_command_with_retry(388-407)UnityMcpBridge/Editor/Helpers/OperationQueue.cs (1)
List(334-347)
UnityMcpBridge/UnityMcpServer~/src/tools/__init__.py (1)
UnityMcpBridge/UnityMcpServer~/src/tools/manage_queue.py (2)
manage_queue(37-131)register_manage_queue(13-227)
UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs (7)
UnityMcpBridge/Editor/MCPForUnityBridge.cs (9)
MCPForUnityBridge(104-125)IsAutoConnectMode(62-62)GetCurrentPort(61-61)Stop(356-414)Start(237-354)System(568-613)System(615-619)System(621-640)System(642-659)UnityMcpBridge/Editor/Helpers/ServerInstaller.cs (5)
ServerInstaller(12-738)GetServerPath(112-115)RepairPythonEnvironment(421-522)FindUvPath(524-712)EnsureServerInstalled(22-110)UnityMcpBridge/Editor/Helpers/PackageDetector.cs (1)
ReadEmbeddedVersionOrFallback(61-74)UnityMcpBridge/Editor/Helpers/ExecPath.cs (2)
ExecPath(10-276)ResolveClaude(15-88)UnityMcpBridge/Editor/Helpers/ConfigJsonBuilder.cs (2)
ConfigJsonBuilder(7-128)BuildManualConfigJson(9-29)UnityMcpBridge/Editor/Windows/ManualConfigEditorWindow.cs (2)
ManualConfigEditorWindow(9-288)ShowWindow(19-27)UnityMcpBridge/Editor/Helpers/ServerPathResolver.cs (2)
ServerPathResolver(7-147)TryFindEmbeddedServerSource(14-99)
UnityMcpBridge/Editor/Helpers/ServerInstaller.cs (1)
UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs (1)
FindUvPath(2046-2049)
UnityMcpBridge/Editor/Tools/ManageScene.cs (1)
UnityMcpBridge/Editor/Helpers/Response.cs (3)
Response(12-190)Success(20-35)Error(43-62)
TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/ManageScriptValidationTests.cs (1)
UnityMcpBridge/Editor/Tools/ManageScript.cs (2)
ManageScript(51-2560)HandleCommand(110-296)
tests/test_operation_queue.py (3)
UnityMcpBridge/UnityMcpServer~/src/tools/manage_queue.py (3)
manage_queue(37-131)register_manage_queue(13-227)queue_batch_operations(144-227)tools/benchmark_operation_queue.py (1)
main(352-400)tools/test_async_queue.py (1)
main(228-280)
TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/ManageGameObjectTests.cs (2)
TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/AIPropertyMatchingTests.cs (15)
SetUp(12-28)Test(30-39)Test(41-47)Test(49-55)Test(57-63)Test(65-71)Test(73-80)Test(82-90)Test(92-98)Test(100-107)Test(109-116)Test(118-131)Test(133-145)Test(147-156)Test(158-166)UnityMcpBridge/Editor/Tools/ManageGameObject.cs (10)
GameObject(1191-1214)ManageGameObject(21-2191)HandleCommand(40-173)ComponentResolver(2197-2457)TryResolve(2207-2243)List(1219-1378)List(2258-2295)List(2318-2336)List(2341-2380)List(2388-2423)
tools/benchmark_operation_queue.py (1)
UnityMcpBridge/UnityMcpServer~/src/unity_connection.py (1)
send_command_with_retry(388-407)
UnityMcpBridge/Editor/Tools/ManageScript.cs (2)
UnityMcpBridge/Editor/Helpers/Response.cs (5)
Response(12-190)EnhancedError(76-114)Success(20-35)ScriptError(139-150)Error(43-62)UnityMcpBridge/Editor/MCPForUnityBridge.cs (4)
System(568-613)System(615-619)System(621-640)System(642-659)
UnityMcpBridge/Editor/Tools/ManageQueue.cs (2)
UnityMcpBridge/Editor/Helpers/Response.cs (4)
Response(12-190)EnhancedError(76-114)Success(20-35)Error(43-62)UnityMcpBridge/Editor/Helpers/OperationQueue.cs (11)
AddOperation(66-97)ExecuteBatch(259-270)ClearQueue(354-374)GetQueueStats(379-398)RemoveOperation(403-410)CancelOperation(415-430)OperationQueue(25-431)List(334-347)QueuedOperation(30-42)Task(124-253)Task(275-290)
UnityMcpBridge/Editor/Helpers/GameObjectSerializer.cs (1)
UnityMcpBridge/Editor/Tools/ManageGameObject.cs (6)
Type(2176-2190)List(1219-1378)List(2258-2295)List(2318-2336)List(2341-2380)List(2388-2423)
UnityMcpBridge/Editor/MCPForUnityBridge.cs (3)
UnityMcpBridge/Editor/Models/Command.cs (1)
Command(8-19)UnityMcpBridge/Editor/Tools/ManageQueue.cs (2)
ManageQueue(17-510)HandleCommand(22-83)UnityMcpBridge/Editor/Helpers/ServerInstaller.cs (2)
ServerInstaller(12-738)GetServerPath(112-115)
🪛 LanguageTool
TestProjects/UnityMCPTests/.serena/memories/code_style_conventions.md
[style] ~30-~30: ‘with success’ might be wordy. Consider a shorter alternative.
Context: ...ocks - Return structured JSON responses with success/error fields - Log detailed errors to U...
(EN_WORDINESS_PREMIUM_WITH_SUCCESS)
🪛 markdownlint-cli2 (0.18.1)
CLAUDE.md
9-9: Bare URL used
(MD034, no-bare-urls)
10-10: Bare URL used
(MD034, no-bare-urls)
184-184: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
README.md
10-10: Bare URL used
(MD034, no-bare-urls)
334-334: Unordered list indentation
Expected: 2; Actual: 4
(MD007, ul-indent)
335-335: Unordered list indentation
Expected: 2; Actual: 4
(MD007, ul-indent)
336-336: Unordered list indentation
Expected: 2; Actual: 4
(MD007, ul-indent)
337-337: Unordered list indentation
Expected: 2; Actual: 4
(MD007, ul-indent)
README-DEV.md
56-56: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
TestProjects/UnityMCPTests/.serena/memories/unity_bridge_port_management.md
35-35: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
TestProjects/UnityMCPTests/.serena/memories/unity_mcp_local_setup.md
100-100: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🪛 Ruff (0.14.3)
tools/test_async_queue.py
1-1: Shebang is present but file is not executable
(EXE001)
98-98: Unused function argument: operation_ids
(ARG001)
118-118: Unused function argument: operation_ids
(ARG001)
200-200: f-string without any placeholders
Remove extraneous f prefix
(F541)
204-204: String contains ambiguous ℹ (INFORMATION SOURCE). Did you mean i (LATIN SMALL LETTER I)?
(RUF001)
223-223: Do not use bare except
(E722)
223-224: try-except-pass detected, consider logging the exception
(S110)
271-271: Consider moving this statement to an else block
(TRY300)
276-276: Do not catch blind exception: Exception
(BLE001)
UnityMcpBridge/UnityMcpServer~/src/tools/manage_queue.py
38-38: Unused function argument: ctx
(ARG001)
125-125: Do not catch blind exception: Exception
(BLE001)
126-126: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
126-126: Use explicit conversion flag
Replace with conversion flag
(RUF010)
129-129: Use explicit conversion flag
Replace with conversion flag
(RUF010)
221-221: Do not catch blind exception: Exception
(BLE001)
222-222: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
222-222: Use explicit conversion flag
Replace with conversion flag
(RUF010)
225-225: Use explicit conversion flag
Replace with conversion flag
(RUF010)
tests/test_operation_queue.py
238-238: Consider [*add_responses, execute_response] instead of concatenation
Replace with [*add_responses, execute_response]
(RUF005)
tools/benchmark_operation_queue.py
1-1: Shebang is present but file is not executable
(EXE001)
92-92: Local variable response is assigned to but never used
Remove assignment to unused variable response
(F841)
103-103: Do not use bare except
(E722)
103-104: try-except-pass detected, consider logging the exception
(S110)
107-107: Do not catch blind exception: Exception
(BLE001)
126-126: Do not catch blind exception: Exception
(BLE001)
242-242: f-string without any placeholders
Remove extraneous f prefix
(F541)
286-286: Do not catch blind exception: Exception
(BLE001)
346-346: f-string without any placeholders
Remove extraneous f prefix
(F541)
395-395: Do not catch blind exception: Exception
(BLE001)
| #### 🚀 Operation Queuing | ||
| **Priority**: High | **Effort**: 3-4 days | **Impact**: Performance boost | ||
|
|
||
| **Implementation Steps**: | ||
| 1. **Day 1**: Create `OperationQueue.cs` helper class | ||
| 2. **Day 2**: Create `ManageQueue.cs` Unity tool | ||
| 3. **Day 3**: Create `manage_queue.py` Python tool | ||
| 4. **Day 4**: Integration testing and performance validation | ||
|
|
||
| **Files to Create**: | ||
| - `UnityMcpBridge/Editor/Helpers/OperationQueue.cs` | ||
| - `UnityMcpBridge/Editor/Tools/ManageQueue.cs` | ||
| - `UnityMcpBridge/UnityMcpServer~/src/tools/manage_queue.py` | ||
|
|
||
| **Success Metrics**: | ||
| - Batch operations 3x faster than individual calls | ||
| - Unity Editor remains responsive during bulk operations | ||
| - Support for transaction rollback on failure | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clarify whether Operation Queuing is completed or planned.
The roadmap describes Operation Queuing as Phase 1 future work (3-4 days effort) and lists files "to create" (OperationQueue.cs, ManageQueue.cs, manage_queue.py). However, the AI-generated summary indicates these components were already implemented in this PR, along with tests and benchmarking tools.
If the operation queue system is already complete, update this section to mark it as ✅ Completed and describe next steps instead. If it's still planned work, clarify what subset was delivered in this PR.
🤖 Prompt for AI Agents
QUICK_WINS_ROADMAP.md lines 25-43: The roadmap currently lists "Operation
Queuing" as future work and files "to create", but the PR and AI summary claim
the queue, tests, and benchmarking were implemented; update the section to match
reality by either (A) marking the feature as ✅ Completed and replacing the
"Files to Create" list with files actually added, a short summary of what was
delivered (implementation, tests, benchmarks), and next steps (e.g., monitoring,
improvements), or (B) if only a subset was delivered, explicitly state what was
included in this PR (e.g., OperationQueue.cs implemented, ManageQueue.cs
scaffolded, tests added, benchmarking tool pending) and keep the remaining items
as planned with adjusted effort/impact; ensure wording is unambiguous about
completion status and list exact filenames and artifacts that exist in the repo.
| for i in range(operation_count): | ||
| operation = self.test_operations[i % len(self.test_operations)] | ||
| try: | ||
| response = send_command_with_retry(operation["tool"], operation["parameters"]) | ||
| if isinstance(response, dict) and response.get("success"): | ||
| successful += 1 | ||
| else: | ||
| failed += 1 | ||
| except Exception as e: | ||
| print(f"Operation {i} failed: {e}") | ||
| failed += 1 | ||
|
|
||
| end_time = time.time() | ||
| execution_time_ms = (end_time - start_time) * 1000 | ||
| ops_per_second = operation_count / (execution_time_ms / 1000) if execution_time_ms > 0 else 0 | ||
|
|
||
| return BenchmarkResult( | ||
| operation_count=operation_count, | ||
| execution_time_ms=execution_time_ms, | ||
| successful_operations=successful, | ||
| failed_operations=failed, | ||
| timeout_operations=0, | ||
| method="individual", | ||
| operations_per_second=ops_per_second | ||
| ) | ||
|
|
||
| def benchmark_queue_sync(self, operation_count: int) -> BenchmarkResult: | ||
| """Benchmark synchronous queue execution.""" | ||
| print(f"📊 Running synchronous queue benchmark ({operation_count} operations)...") | ||
|
|
||
| # Clear queue first | ||
| send_command_with_retry("manage_queue", {"action": "clear"}) | ||
|
|
||
| # Add operations to queue | ||
| start_time = time.time() | ||
| for i in range(operation_count): | ||
| operation = self.test_operations[i % len(self.test_operations)] | ||
| send_command_with_retry("manage_queue", { | ||
| "action": "add", | ||
| "tool": operation["tool"], | ||
| "parameters": operation["parameters"], | ||
| "timeout_ms": 30000 | ||
| }) | ||
|
|
||
| # Execute batch synchronously | ||
| response = send_command_with_retry("manage_queue", {"action": "execute"}) | ||
| end_time = time.time() | ||
|
|
||
| execution_time_ms = (end_time - start_time) * 1000 | ||
| ops_per_second = operation_count / (execution_time_ms / 1000) if execution_time_ms > 0 else 0 | ||
|
|
||
| # Extract results | ||
| data = response.get("data", {}) if isinstance(response, dict) else {} | ||
| successful = data.get("successful", 0) | ||
| failed = data.get("failed", 0) | ||
| timeout = data.get("timeout", 0) | ||
|
|
||
| return BenchmarkResult( | ||
| operation_count=operation_count, | ||
| execution_time_ms=execution_time_ms, | ||
| successful_operations=successful, | ||
| failed_operations=failed, | ||
| timeout_operations=timeout, | ||
| method="queue_sync", | ||
| operations_per_second=ops_per_second | ||
| ) | ||
|
|
||
| def benchmark_queue_async(self, operation_count: int) -> BenchmarkResult: | ||
| """Benchmark asynchronous queue execution.""" | ||
| print(f"📊 Running asynchronous queue benchmark ({operation_count} operations)...") | ||
|
|
||
| # Clear queue first | ||
| send_command_with_retry("manage_queue", {"action": "clear"}) | ||
|
|
||
| # Add operations to queue | ||
| start_time = time.time() | ||
| for i in range(operation_count): | ||
| operation = self.test_operations[i % len(self.test_operations)] | ||
| send_command_with_retry("manage_queue", { | ||
| "action": "add", | ||
| "tool": operation["tool"], | ||
| "parameters": operation["parameters"], | ||
| "timeout_ms": 30000 | ||
| }) | ||
|
|
||
| # Execute batch asynchronously and monitor progress | ||
| send_command_with_retry("manage_queue", {"action": "execute_async"}) | ||
|
|
||
| # Poll for completion | ||
| while True: | ||
| stats = send_command_with_retry("manage_queue", {"action": "stats"}) | ||
| if isinstance(stats, dict) and stats.get("success"): | ||
| data = stats.get("data", {}) | ||
| executing = data.get("executing", 0) | ||
| pending = data.get("pending", 0) | ||
|
|
||
| if executing == 0 and pending == 0: | ||
| break | ||
| time.sleep(0.1) # Poll every 100ms | ||
|
|
||
| end_time = time.time() | ||
|
|
||
| execution_time_ms = (end_time - start_time) * 1000 | ||
| ops_per_second = operation_count / (execution_time_ms / 1000) if execution_time_ms > 0 else 0 | ||
|
|
||
| # Get final stats | ||
| final_stats = send_command_with_retry("manage_queue", {"action": "stats"}) | ||
| data = final_stats.get("data", {}) if isinstance(final_stats, dict) else {} | ||
| successful = data.get("executed", 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix response parsing to match Unity MCP envelope
send_command_with_retry returns the Unity-side envelope { "status": "...", "result": { "success": ..., "data": ... } }. Every place we probe response.get("success")/response.get("data") therefore reads None, so we mark all runs as failures and the async polling loop never exits. That makes the benchmark unusable.
Patch the envelope handling (and repeat the same pattern for the other call sites in this file):
- response = send_command_with_retry(operation["tool"], operation["parameters"])
- if isinstance(response, dict) and response.get("success"):
- successful += 1
- else:
- failed += 1
+ response = send_command_with_retry(operation["tool"], operation["parameters"])
+ if isinstance(response, dict) and response.get("status") == "success":
+ result_payload = response.get("result", {}) or {}
+ if result_payload.get("success"):
+ successful += 1
+ else:
+ failed += 1
+ else:
+ failed += 1
...
- response = send_command_with_retry("manage_queue", {"action": "execute"})
+ response = send_command_with_retry("manage_queue", {"action": "execute"})
+ result_payload = response.get("result", {}) if isinstance(response, dict) else {}
- data = response.get("data", {}) if isinstance(response, dict) else {}
+ data = result_payload.get("data", {}) if isinstance(result_payload, dict) else {}
...
- stats = send_command_with_retry("manage_queue", {"action": "stats"})
- if isinstance(stats, dict) and stats.get("success"):
- data = stats.get("data", {})
+ stats = send_command_with_retry("manage_queue", {"action": "stats"})
+ if isinstance(stats, dict) and stats.get("status") == "success":
+ data = stats.get("result", {}).get("data", {}) or {}Update every similar block so we consistently unwrap result before checking success or data.
🧰 Tools
🪛 Ruff (0.14.3)
126-126: Do not catch blind exception: Exception
(BLE001)
🤖 Prompt for AI Agents
In tools/benchmark_operation_queue.py around lines 118 to 226, the code
incorrectly reads response.get("success") and response.get("data") directly but
send_command_with_retry returns the Unity MCP envelope { "status": "...",
"result": { "success": ..., "data": ... } }; update all response handling here
to first check the top-level response is a dict and then unwrap result =
response.get("result", {}) (or handle missing result safely) before checking
result.get("success") and result.get("data") (and similarly use
result.get("executed"/"successful"/"failed"/"timeout"/"executing"/"pending")
where applicable); apply this same unwrapping pattern to every other call site
in the file so success/data checks and the async polling loop use the inner
result object.
| private static async Task<object> ExecuteOperationWithTimeoutAsync(QueuedOperation operation) | ||
| { | ||
| var cancellationTokenSource = new CancellationTokenSource(operation.TimeoutMs); | ||
|
|
||
| try | ||
| { | ||
| // Execute on Unity's main thread with timeout | ||
| var task = Task.Run(() => ExecuteOperation(operation), cancellationTokenSource.Token); | ||
|
|
||
| return await task; | ||
| } | ||
| catch (OperationCanceledException) | ||
| { | ||
| throw new TimeoutException($"Operation {operation.Id} timed out after {operation.TimeoutMs}ms"); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Critical: Async execution may fail due to Unity threading constraints.
Unity Editor APIs (AssetDatabase, EditorApplication, etc.) must be called from the main thread. Using Task.Run() executes operations on a thread pool thread, which will cause "Can only be called from main thread" exceptions.
Consider these approaches:
Option 1: Execute synchronously with yield for UI responsiveness
private static async Task<object> ExecuteOperationWithTimeoutAsync(QueuedOperation operation)
{
- var cancellationTokenSource = new CancellationTokenSource(operation.TimeoutMs);
-
- try
- {
- // Execute on Unity's main thread with timeout
- var task = Task.Run(() => ExecuteOperation(operation), cancellationTokenSource.Token);
-
- return await task;
- }
- catch (OperationCanceledException)
- {
- throw new TimeoutException($"Operation {operation.Id} timed out after {operation.TimeoutMs}ms");
- }
+ var startTime = DateTime.UtcNow;
+
+ // Execute on main thread (we're already on it)
+ var result = ExecuteOperation(operation);
+
+ // Check timeout after execution
+ var elapsed = (DateTime.UtcNow - startTime).TotalMilliseconds;
+ if (elapsed > operation.TimeoutMs)
+ {
+ throw new TimeoutException($"Operation {operation.Id} timed out after {elapsed}ms");
+ }
+
+ return result;
}Option 2: Use Unity's async infrastructure
If you need true async with timeout, use Unity's EditorApplication.delayCall or coroutines with a timeout mechanism that checks elapsed time between yields.
The synchronous ExecuteBatch() wrapper is actually safer for Unity operations.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| private static async Task<object> ExecuteOperationWithTimeoutAsync(QueuedOperation operation) | |
| { | |
| var cancellationTokenSource = new CancellationTokenSource(operation.TimeoutMs); | |
| try | |
| { | |
| // Execute on Unity's main thread with timeout | |
| var task = Task.Run(() => ExecuteOperation(operation), cancellationTokenSource.Token); | |
| return await task; | |
| } | |
| catch (OperationCanceledException) | |
| { | |
| throw new TimeoutException($"Operation {operation.Id} timed out after {operation.TimeoutMs}ms"); | |
| } | |
| } | |
| private static async Task<object> ExecuteOperationWithTimeoutAsync(QueuedOperation operation) | |
| { | |
| var startTime = DateTime.UtcNow; | |
| // Execute on main thread (we're already on it) | |
| var result = ExecuteOperation(operation); | |
| // Check timeout after execution | |
| var elapsed = (DateTime.UtcNow - startTime).TotalMilliseconds; | |
| if (elapsed > operation.TimeoutMs) | |
| { | |
| throw new TimeoutException($"Operation {operation.Id} timed out after {elapsed}ms"); | |
| } | |
| return result; | |
| } |
| var similarAssets = new List<string>(); | ||
|
|
||
| if (System.IO.Directory.Exists(directory)) | ||
| { | ||
| var files = System.IO.Directory.GetFiles(directory, "*" + fileName + "*", System.IO.SearchOption.TopDirectoryOnly); | ||
| foreach (var file in files.Take(3)) // Limit to 3 suggestions | ||
| { | ||
| var relativePath = file.Replace(Application.dataPath, "Assets"); | ||
| if (relativePath != assetPath) // Don't include the failed path itself | ||
| similarAssets.Add(relativePath); | ||
| } | ||
| } | ||
|
|
||
| return similarAssets.ToArray(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Normalize Windows paths before filtering duplicates
Application.dataPath returns forward slashes even on Windows, but Directory.GetFiles yields backslash paths. Because of that mismatch, the Replace never triggers on Windows, so relativePath stays an absolute path with a drive letter. Two side-effects follow: (1) callers see raw absolute paths in related_items, and (2) the relativePath != assetPath guard stops working, so we re-suggest the exact asset that just failed. Please normalize separators on both strings (and compare case-insensitively) before deriving the relative path so we only return genuinely similar assets.
Apply this diff to normalize the paths:
- var files = System.IO.Directory.GetFiles(directory, "*" + fileName + "*", System.IO.SearchOption.TopDirectoryOnly);
- foreach (var file in files.Take(3)) // Limit to 3 suggestions
- {
- var relativePath = file.Replace(Application.dataPath, "Assets");
- if (relativePath != assetPath) // Don't include the failed path itself
- similarAssets.Add(relativePath);
- }
+ var files = System.IO.Directory.GetFiles(directory, "*" + fileName + "*", System.IO.SearchOption.TopDirectoryOnly);
+ var normalizedDataPath = Application.dataPath.Replace('\\', '/');
+ foreach (var file in files.Take(3)) // Limit to 3 suggestions
+ {
+ var normalizedFile = file.Replace('\\', '/');
+ var relativePath = normalizedFile.StartsWith(normalizedDataPath, StringComparison.OrdinalIgnoreCase)
+ ? "Assets" + normalizedFile.Substring(normalizedDataPath.Length)
+ : normalizedFile;
+
+ if (!string.Equals(relativePath, assetPath, StringComparison.OrdinalIgnoreCase)) // Don't include the failed path itself
+ {
+ similarAssets.Add(relativePath);
+ }
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| var similarAssets = new List<string>(); | |
| if (System.IO.Directory.Exists(directory)) | |
| { | |
| var files = System.IO.Directory.GetFiles(directory, "*" + fileName + "*", System.IO.SearchOption.TopDirectoryOnly); | |
| foreach (var file in files.Take(3)) // Limit to 3 suggestions | |
| { | |
| var relativePath = file.Replace(Application.dataPath, "Assets"); | |
| if (relativePath != assetPath) // Don't include the failed path itself | |
| similarAssets.Add(relativePath); | |
| } | |
| } | |
| return similarAssets.ToArray(); | |
| var similarAssets = new List<string>(); | |
| if (System.IO.Directory.Exists(directory)) | |
| { | |
| var files = System.IO.Directory.GetFiles(directory, "*" + fileName + "*", System.IO.SearchOption.TopDirectoryOnly); | |
| var normalizedDataPath = Application.dataPath.Replace('\\', '/'); | |
| foreach (var file in files.Take(3)) // Limit to 3 suggestions | |
| { | |
| var normalizedFile = file.Replace('\\', '/'); | |
| var relativePath = normalizedFile.StartsWith(normalizedDataPath, StringComparison.OrdinalIgnoreCase) | |
| ? "Assets" + normalizedFile.Substring(normalizedDataPath.Length) | |
| : normalizedFile; | |
| if (!string.Equals(relativePath, assetPath, StringComparison.OrdinalIgnoreCase)) // Don't include the failed path itself | |
| { | |
| similarAssets.Add(relativePath); | |
| } | |
| } | |
| } | |
| return similarAssets.ToArray(); |
🤖 Prompt for AI Agents
In UnityMcpBridge/Editor/Helpers/Response.cs around lines 170 to 183,
Directory.GetFiles can return backslash paths on Windows while
Application.dataPath uses forward slashes, so the Replace and duplicate filter
fail; fix by normalizing path separators (e.g., replace '\' with '/' on both the
file path and Application.dataPath), perform a case-insensitive comparison when
checking relativePath != assetPath (use invariant lowercase), then strip the
normalized Application.dataPath prefix to produce a proper "Assets/..." relative
path before adding to similarAssets so callers never see absolute drive-letter
paths and the failed asset is not re-suggested.
| // Execute the operation | ||
| var result = await Task.Run(() => | ||
| { | ||
| try | ||
| { | ||
| switch (operation.Tool.ToLowerInvariant()) | ||
| { | ||
| case "manage_script": | ||
| return Tools.ManageScript.HandleCommand(operation.Parameters); | ||
| case "manage_asset": | ||
| return Tools.ManageAsset.HandleCommand(operation.Parameters); | ||
| case "manage_scene": | ||
| return Tools.ManageScene.HandleCommand(operation.Parameters); | ||
| case "manage_gameobject": | ||
| return Tools.ManageGameObject.HandleCommand(operation.Parameters); | ||
| case "manage_shader": | ||
| return Tools.ManageShader.HandleCommand(operation.Parameters); | ||
| case "manage_editor": | ||
| return Tools.ManageEditor.HandleCommand(operation.Parameters); | ||
| case "read_console": | ||
| return Tools.ReadConsole.HandleCommand(operation.Parameters); | ||
| case "execute_menu_item": | ||
| return Tools.ExecuteMenuItem.HandleCommand(operation.Parameters); | ||
| default: | ||
| throw new ArgumentException($"Unknown tool: {operation.Tool}"); | ||
| } | ||
| } | ||
| catch (Exception e) | ||
| { | ||
| throw new Exception($"Operation {operation.Id} failed: {e.Message}", e); | ||
| } | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid running Unity editor commands on background threads
Task.Run shifts ManageScript/ManageAsset/… handlers onto a worker thread, but those handlers are saturated with UnityEditor and scene APIs that must execute on the main thread. Under load this will trigger UnityException: get_isActiveAndEnabled can only be called from the main thread, duplicated work, or outright editor crashes. We still get UI responsiveness from the surrounding await Task.Yield(); run the handlers in-process and drop the background dispatch.
Apply this diff (and the analogous result = …; break; assignments for every case):
- var result = await Task.Run(() =>
- {
- try
- {
- switch (operation.Tool.ToLowerInvariant())
- {
- case "manage_script":
- return Tools.ManageScript.HandleCommand(operation.Parameters);
- case "manage_asset":
- return Tools.ManageAsset.HandleCommand(operation.Parameters);
- case "manage_scene":
- return Tools.ManageScene.HandleCommand(operation.Parameters);
- case "manage_gameobject":
- return Tools.ManageGameObject.HandleCommand(operation.Parameters);
- case "manage_shader":
- return Tools.ManageShader.HandleCommand(operation.Parameters);
- case "manage_editor":
- return Tools.ManageEditor.HandleCommand(operation.Parameters);
- case "read_console":
- return Tools.ReadConsole.HandleCommand(operation.Parameters);
- case "execute_menu_item":
- return Tools.ExecuteMenuItem.HandleCommand(operation.Parameters);
- default:
- throw new ArgumentException($"Unknown tool: {operation.Tool}");
- }
- }
- catch (Exception e)
- {
- throw new Exception($"Operation {operation.Id} failed: {e.Message}", e);
- }
- });
+ object result;
+ try
+ {
+ switch (operation.Tool.ToLowerInvariant())
+ {
+ case "manage_script":
+ result = Tools.ManageScript.HandleCommand(operation.Parameters);
+ break;
+ case "manage_asset":
+ result = Tools.ManageAsset.HandleCommand(operation.Parameters);
+ break;
+ case "manage_scene":
+ result = Tools.ManageScene.HandleCommand(operation.Parameters);
+ break;
+ case "manage_gameobject":
+ result = Tools.ManageGameObject.HandleCommand(operation.Parameters);
+ break;
+ case "manage_shader":
+ result = Tools.ManageShader.HandleCommand(operation.Parameters);
+ break;
+ case "manage_editor":
+ result = Tools.ManageEditor.HandleCommand(operation.Parameters);
+ break;
+ case "read_console":
+ result = Tools.ReadConsole.HandleCommand(operation.Parameters);
+ break;
+ case "execute_menu_item":
+ result = Tools.ExecuteMenuItem.HandleCommand(operation.Parameters);
+ break;
+ default:
+ throw new ArgumentException($"Unknown tool: {operation.Tool}");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new Exception($"Operation {operation.Id} failed: {e.Message}", e);
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Execute the operation | |
| var result = await Task.Run(() => | |
| { | |
| try | |
| { | |
| switch (operation.Tool.ToLowerInvariant()) | |
| { | |
| case "manage_script": | |
| return Tools.ManageScript.HandleCommand(operation.Parameters); | |
| case "manage_asset": | |
| return Tools.ManageAsset.HandleCommand(operation.Parameters); | |
| case "manage_scene": | |
| return Tools.ManageScene.HandleCommand(operation.Parameters); | |
| case "manage_gameobject": | |
| return Tools.ManageGameObject.HandleCommand(operation.Parameters); | |
| case "manage_shader": | |
| return Tools.ManageShader.HandleCommand(operation.Parameters); | |
| case "manage_editor": | |
| return Tools.ManageEditor.HandleCommand(operation.Parameters); | |
| case "read_console": | |
| return Tools.ReadConsole.HandleCommand(operation.Parameters); | |
| case "execute_menu_item": | |
| return Tools.ExecuteMenuItem.HandleCommand(operation.Parameters); | |
| default: | |
| throw new ArgumentException($"Unknown tool: {operation.Tool}"); | |
| } | |
| } | |
| catch (Exception e) | |
| { | |
| throw new Exception($"Operation {operation.Id} failed: {e.Message}", e); | |
| } | |
| }); | |
| object result; | |
| try | |
| { | |
| switch (operation.Tool.ToLowerInvariant()) | |
| { | |
| case "manage_script": | |
| result = Tools.ManageScript.HandleCommand(operation.Parameters); | |
| break; | |
| case "manage_asset": | |
| result = Tools.ManageAsset.HandleCommand(operation.Parameters); | |
| break; | |
| case "manage_scene": | |
| result = Tools.ManageScene.HandleCommand(operation.Parameters); | |
| break; | |
| case "manage_gameobject": | |
| result = Tools.ManageGameObject.HandleCommand(operation.Parameters); | |
| break; | |
| case "manage_shader": | |
| result = Tools.ManageShader.HandleCommand(operation.Parameters); | |
| break; | |
| case "manage_editor": | |
| result = Tools.ManageEditor.HandleCommand(operation.Parameters); | |
| break; | |
| case "read_console": | |
| result = Tools.ReadConsole.HandleCommand(operation.Parameters); | |
| break; | |
| case "execute_menu_item": | |
| result = Tools.ExecuteMenuItem.HandleCommand(operation.Parameters); | |
| break; | |
| default: | |
| throw new ArgumentException($"Unknown tool: {operation.Tool}"); | |
| } | |
| } | |
| catch (Exception e) | |
| { | |
| throw new Exception($"Operation {operation.Id} failed: {e.Message}", e); | |
| } |
| if (MCPForUnityBridge.IsRunning) | ||
| { | ||
| MCPForUnityBridge.Stop(); | ||
| EditorApplication.delayCall += () => | ||
| { | ||
| MCPForUnityBridge.Start(); | ||
| Repaint(); | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Auto-connect mode is lost after setting a manual port
When the bridge is running in auto-connect mode, StartAutoConnect() sets isAutoConnectMode = true. This block always restarts with MCPForUnityBridge.Start(), which resets isAutoConnectMode to false, so the bridge silently drops back to manual mode after a port change. Users expecting the editor to keep auto-restarting will now lose that behavior. Please preserve the prior mode (e.g., cache MCPForUnityBridge.IsAutoConnectMode() before stopping and call StartAutoConnect() when appropriate).
Apply this diff:
- if (MCPForUnityBridge.IsRunning)
+ var wasAutoConnect = MCPForUnityBridge.IsAutoConnectMode();
+ if (MCPForUnityBridge.IsRunning)
{
MCPForUnityBridge.Stop();
EditorApplication.delayCall += () =>
{
- MCPForUnityBridge.Start();
+ if (wasAutoConnect)
+ {
+ MCPForUnityBridge.StartAutoConnect();
+ }
+ else
+ {
+ MCPForUnityBridge.Start();
+ }
Repaint();
};
}
+ else if (wasAutoConnect)
+ {
+ MCPForUnityBridge.StartAutoConnect();
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (MCPForUnityBridge.IsRunning) | |
| { | |
| MCPForUnityBridge.Stop(); | |
| EditorApplication.delayCall += () => | |
| { | |
| MCPForUnityBridge.Start(); | |
| Repaint(); | |
| }; | |
| var wasAutoConnect = MCPForUnityBridge.IsAutoConnectMode(); | |
| if (MCPForUnityBridge.IsRunning) | |
| { | |
| MCPForUnityBridge.Stop(); | |
| EditorApplication.delayCall += () => | |
| { | |
| if (wasAutoConnect) | |
| { | |
| MCPForUnityBridge.StartAutoConnect(); | |
| } | |
| else | |
| { | |
| MCPForUnityBridge.Start(); | |
| } | |
| Repaint(); | |
| }; | |
| } | |
| else if (wasAutoConnect) | |
| { | |
| MCPForUnityBridge.StartAutoConnect(); | |
| } |
🤖 Prompt for AI Agents
In UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs around lines 717 to
724, stopping and restarting the bridge unconditionally calls
MCPForUnityBridge.Start(), which clears auto-connect mode; capture the current
auto-connect state before calling MCPForUnityBridge.Stop(), then on delayed
restart call MCPForUnityBridge.StartAutoConnect() if the captured value
indicates auto-connect was enabled, otherwise call MCPForUnityBridge.Start();
ensure you read the mode via MCPForUnityBridge.IsAutoConnectMode() (or
equivalent) and use that cached value inside the EditorApplication.delayCall
closure so the prior mode is preserved after the restart.
|
Please refer to this comment on an earlier PR: #372 (comment) |
Show package name and version change (old → new) in Discord notifications.
Changes:
name: old → neworname: version (new package)Published: X | Skipped: YSee: The1Studio/UPMAutoPublisher@6eabc7b
Summary by CodeRabbit
New Features
Documentation