[Feature] manage_camera with cinemachine support#882
[Feature] manage_camera with cinemachine support#882Scriptwonder merged 7 commits intoCoplayDev:betafrom
Conversation
Reviewer's GuideIntroduces a new cross-platform Sequence diagram for manage_camera screenshot_multiview flow with shared screenshot utilitiessequenceDiagram
actor Dev as Developer
participant CLI as unity_mcp_cli_camera
participant Tool as manage_camera_tool
participant Utils as utils_py
participant Unity as ManageCamera_cs
participant SceneTool as ManageScene_cs
participant ShotUtil as ScreenshotUtility_cs
Dev->>CLI: unity-mcp camera screenshot-multiview --max-resolution 480
CLI->>Tool: manage_camera(action="screenshot_multiview", max_resolution=480)
Tool->>Utils: build_screenshot_params(params, ...)
Utils-->>Tool: params with batch="surround", includeImage=true
Tool->>Unity: send manage_camera { action: "screenshot_multiview", ... }
Unity->>SceneTool: HandleCommand(action="screenshot", batch="surround", includeImage=true)
SceneTool->>ShotUtil: CaptureToAssetsFolder / camera fallback
ShotUtil-->>SceneTool: image file + imageBase64 data
SceneTool-->>Unity: { success: true, data: { imageBase64, sceneCenter, ... } }
Unity-->>Tool: response dict
Tool->>Utils: extract_screenshot_images(response)
Utils-->>Tool: ToolResult(TextContent + ImageContent)
Tool-->>CLI: ToolResult with JSON + inline PNG image
CLI-->>Dev: formatted output and rendered screenshot
Class diagram for new Unity camera tooling and resourceclassDiagram
class ManageCamera {
+HandleCommand(params JObject) object
}
class CameraCreate {
+CreateBasicCamera(params JObject) object
+CreateCinemachineCamera(params JObject) object
+EnsureBrain(params JObject) object
}
class CameraConfigure {
+SetBasicCameraTarget(params JObject) object
+SetBasicCameraLens(params JObject) object
+SetBasicCameraPriority(params JObject) object
+SetCinemachineTarget(params JObject) object
+SetCinemachineLens(params JObject) object
+SetCinemachinePriority(params JObject) object
+SetBody(params JObject) object
+SetAim(params JObject) object
+SetNoise(params JObject) object
+AddExtension(params JObject) object
+RemoveExtension(params JObject) object
}
class CameraControl {
+ListCameras(params JObject) object
+GetBrainStatus(params JObject) object
+SetBlend(params JObject) object
+ForceCamera(params JObject) object
+ReleaseOverride(params JObject) object
-int _overrideId
}
class CameraHelpers {
-bool? _hasCinemachine
-Type _cmCameraType
-Type _cmBrainType
+bool HasCinemachine
+Type CinemachineCameraType
+Type CinemachineBrainType
+string GetCinemachineVersion()
+GameObject FindTargetGameObject(params JObject)
+GameObject ResolveGameObjectRef(reference object)
+Component FindCinemachineCamera(params JObject)
+Component FindBrain()
+Camera FindMainCamera()
+JObject ExtractProperties(params JObject)
+object GetReflectionProperty(component Component, propertyName string)
+int ReadCinemachinePriority(cmCamera Component)
+bool SetReflectionProperty(component Component, propertyName string, value object)
+void SetTransformTarget(cmCamera Component, propertyName string, targetRef JToken)
+Type ResolveComponentType(typeName string)
+Component GetPipelineComponent(cmCamera Component, stageName string)
+string GetFallbackSuggestion(action string)
+void MarkDirty(go GameObject)
}
class CamerasResource {
+HandleCommand(params JObject) object
}
class ManageScene {
+HandleCommand(params JObject) object
}
ManageCamera ..> CameraCreate : uses
ManageCamera ..> CameraConfigure : uses
ManageCamera ..> CameraControl : uses
ManageCamera ..> CameraHelpers : checks Cinemachine and fallbacks
ManageCamera ..> ManageScene : delegates screenshot actions
CameraCreate ..> CameraHelpers : uses
CameraConfigure ..> CameraHelpers : uses
CameraControl ..> CameraHelpers : uses
CamerasResource ..> CameraControl : calls ListCameras
CameraHelpers <.. CamerasResource : shared type information
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (27)
📝 WalkthroughWalkthroughAdds a new camera management feature: editor-side camera tools (create/configure/control), Cinemachine-aware helpers, a cameras resource, ManageCamera dispatcher, CLI/server tool endpoints, centralized screenshot parameter handling and image extraction, tests, docs and manifest updates. Changes
Sequence Diagram(s)sequenceDiagram
participant CLI as CLI/Service
participant Server as Python MCP Server
participant Unity as Unity Editor (C#)
participant CM as Cinemachine
CLI->>Server: manage_camera(action, params)
Server->>Server: validate action, build params
Server->>Unity: send HandleCommand(action, params)
activate Unity
Unity->>Unity: ManageCamera dispatch -> CameraCreate/CameraConfigure/CameraControl
alt action requires Cinemachine
Unity->>CM: reflect-access components
CM-->>Unity: component info/state
Unity->>Unity: modify SerializedObject, set properties, Undo/MarkDirty
else basic camera
Unity->>Unity: modify Camera component properties, mark dirty
end
Unity-->>Server: result (may include inline images/base64)
deactivate Unity
Server->>Server: extract_screenshot_images if present
Server-->>CLI: return result
sequenceDiagram
participant Client as API client
participant Server as Python MCP Server
participant Unity as Unity Editor (C#)
participant CameraControl as CameraControl helper
Client->>Server: GET mcpforunity://scene/cameras
Server->>Unity: send get_cameras command
activate Unity
Unity->>CameraControl: ListCameras(params)
CameraControl->>CameraControl: detect Cinemachine, enumerate cameras & brains
CameraControl-->>Unity: consolidated camera list
Unity-->>Server: response
deactivate Unity
Server-->>Client: MCPResponse with camera list
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
✨ 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.
Hey - I've found 1 issue, and left some high level feedback:
- In
CameraCreate.EnsureBrain, thedefaultBlendStylehandling mixesSerializedObjectandComponentOps.SetPropertyon the "DefaultBlend.Style" path; since you already havedefaultBlendProp, it would be more reliable and consistent withSetBlendto drive the enum directly via aSerializedProperty(Style/m_Style) instead of using the generic reflection helper on a nested path. - The camera override mechanism in
CameraControl.ForceCamerastores_overrideIdin a single static field; if you ever support multiple brains or domain reload scenarios, you may want to scope the override id to the specific brain instance (or reset it more explicitly) to avoid leaking override state between brains.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `CameraCreate.EnsureBrain`, the `defaultBlendStyle` handling mixes `SerializedObject` and `ComponentOps.SetProperty` on the "DefaultBlend.Style" path; since you already have `defaultBlendProp`, it would be more reliable and consistent with `SetBlend` to drive the enum directly via a `SerializedProperty` (`Style`/`m_Style`) instead of using the generic reflection helper on a nested path.
- The camera override mechanism in `CameraControl.ForceCamera` stores `_overrideId` in a single static field; if you ever support multiple brains or domain reload scenarios, you may want to scope the override id to the specific brain instance (or reset it more explicitly) to avoid leaking override state between brains.
## Individual Comments
### Comment 1
<location path="MCPForUnity/Editor/Tools/Cameras/CameraCreate.cs" line_range="217-218" />
<code_context>
+ {
+ var styleProp = defaultBlendProp.FindPropertyRelative("Style")
+ ?? defaultBlendProp.FindPropertyRelative("m_Style");
+ if (styleProp != null)
+ ComponentOps.SetProperty(brain, "DefaultBlend.Style", new JValue(blendStyle), out _);
+ }
+ if (blendDuration >= 0)
</code_context>
<issue_to_address>
**issue (bug_risk):** Default blend style on CinemachineBrain is likely not being updated as intended.
Here you resolve `Style` to a `SerializedProperty` (`styleProp`) but then ignore it and call `ComponentOps.SetProperty(brain, "DefaultBlend.Style", ...)`. Unless `ComponentOps` explicitly knows how to drill into `DefaultBlend`, this likely does nothing or fails silently.
Given you already have `styleProp` as an enum `SerializedProperty`, consider mapping `blendStyle` to the enum and setting `styleProp.enumValueIndex` directly (as in `CameraControl.SetBlend`). That avoids relying on `ComponentOps` for nested struct fields and ensures the value is actually applied.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
…unity-mcp into camera/cinemachine
There was a problem hiding this comment.
Pull request overview
This PR adds a new manage_camera tool for AI-driven camera control in Unity with optional Cinemachine integration (tiered fallback support), a new cameras resource, and fixes a compile-time error when the Unity Screen Capture module is disabled.
Changes:
- New
manage_cameraPython tool and C# handler with 18 actions (setup, create, configure, extend, control, capture), split acrossManageCamera.cs,CameraHelpers.cs,CameraCreate.cs,CameraControl.cs, andCameraConfigure.cs - Screenshot handling logic extracted from
manage_scene.pyinto shared utilities (build_screenshot_params,extract_screenshot_images) inutils.py, consumed by bothmanage_sceneandmanage_camera - Bug fix:
ScreenshotUtility.csuses reflection to callScreenCapture.CaptureScreenshotso the code compiles even when the Screen Capture module is disabled
Reviewed changes
Copilot reviewed 27 out of 28 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
Server/src/services/tools/manage_camera.py |
New Python tool with 18 camera actions, Cinemachine-aware |
Server/src/services/tools/utils.py |
New shared build_screenshot_params and extract_screenshot_images utilities |
Server/src/services/tools/manage_scene.py |
Refactored to delegate screenshot param handling to shared utilities |
Server/src/services/resources/cameras.py |
New cameras resource at mcpforunity://scene/cameras |
Server/src/cli/commands/camera.py |
New CLI command group for all camera actions |
Server/src/cli/main.py |
Registers the new camera CLI command |
Server/tests/test_manage_camera.py |
Comprehensive tests for the new manage_camera tool |
Server/tests/integration/test_manage_scene_screenshot_params.py |
Updated to use the new shared extract_screenshot_images utility |
MCPForUnity/Editor/Tools/Cameras/ManageCamera.cs |
Main C# handler dispatching camera actions, tiered Cinemachine support |
MCPForUnity/Editor/Tools/Cameras/CameraHelpers.cs |
Shared helpers for Cinemachine detection, GameObject lookup, reflection |
MCPForUnity/Editor/Tools/Cameras/CameraCreate.cs |
Camera and brain creation with preset support |
MCPForUnity/Editor/Tools/Cameras/CameraControl.cs |
Blend, force/release override, list cameras, brain status |
MCPForUnity/Editor/Tools/Cameras/CameraConfigure.cs |
Lens, target, priority, body, aim, noise, extension configuration |
MCPForUnity/Editor/Resources/Scene/CamerasResource.cs |
C# handler for the get_cameras resource |
MCPForUnity/Runtime/Helpers/ScreenshotUtility.cs |
Fix compile error when Screen Capture module is disabled (issue #863) |
MCPForUnity/Editor/Windows/Components/Tools/McpToolsSection.cs |
Adds screenshot action buttons to the manage_camera tool row in Editor UI |
manifest.json |
Version bumped to 9.5.2, adds manage_camera and manage_probuilder entries |
README.md / docs/i18n/README-zh.md |
Updated tool/resource lists and release notes |
Server/uv.lock |
Lock file updated |
tools/UPDATE_DOCS_PROMPT.md |
Added README/changelog update instructions |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| """Camera CLI commands for managing Unity Camera + Cinemachine.""" | ||
|
|
||
| import click | ||
| from typing import Optional, Any |
There was a problem hiding this comment.
Optional is imported from typing but is never used in this file. Since Python 3.10+ supports X | None syntax (which is already used throughout this file), this import can be removed.
| from typing import Optional, Any | |
| from typing import Any |
| from typing import Optional, Any | ||
|
|
||
| from cli.utils.config import get_config | ||
| from cli.utils.output import format_output, print_error, print_success |
There was a problem hiding this comment.
The imports print_error and print_success from cli.utils.output are imported but never used in this file. These should be removed to keep the import section clean.
| from cli.utils.output import format_output, print_error, print_success | |
| from cli.utils.output import format_output |
| catch (Exception ex) | ||
| { | ||
| McpLog.Error($"[ManageCamera] Action '{action}' failed: {ex}"); | ||
| return new ErrorResponse($"Error in action '{action}': {ex.Message}"); |
There was a problem hiding this comment.
The catch block in ManageCamera.HandleCommand returns new ErrorResponse($"Error in action '{action}': {ex.Message}") without the stackTrace field. The established codebase convention (consistently followed in ManageMaterial.cs, ManageUI.cs, ManageVFX.cs, ManageProBuilder.cs) is to include the stack trace in the error response data for debugging: new ErrorResponse(ex.Message, new { stackTrace = ex.StackTrace }).
| return new ErrorResponse($"Error in action '{action}': {ex.Message}"); | |
| return new ErrorResponse($"Error in action '{action}': {ex.Message}", new { stackTrace = ex.StackTrace }); |
| } | ||
|
|
||
| if (IsManageSceneTool(tool)) | ||
| if (IsManageSceneTool(tool) || IsManageCameraTool(tool)) |
There was a problem hiding this comment.
The CreateManageSceneActions() method is reused for manage_camera but it adds buttons that invoke OnManageSceneScreenshotClicked() and OnManageSceneMultiviewClicked(), which hardcode calls to ManageScene.ExecuteScreenshot() and ManageScene.ExecuteMultiviewScreenshot(). The tooltip text even says "via manage_scene". When the buttons appear under the manage_camera tool in the editor UI, they still trigger manage_scene functionality, which is functionally correct but misleading to the user. A camera-specific method or a renamed/generic method should be used here.
| if (IsManageSceneTool(tool) || IsManageCameraTool(tool)) | |
| if (IsManageSceneTool(tool)) |
Description
Add a new manage_camera tool for AI-driven camera control in Unity, with optional Cinemachine integration. Also fixes a compile-time error when the Screen Capture module is disabled.
Type of Change
Save your change type
Changes Made
New manage_camera Tool
Testing/Screenshots/Recordings
Documentation Updates
tools/UPDATE_DOCS_PROMPT.md(recommended)tools/UPDATE_DOCS.mdRelated Issues
Fix compile-time error CS0103 (ScreenCapture not found) when the Screen Capture module (com.unity.modules.screencapture) is disabled in Unity noted in #863
Additional Notes
Also notice the fastMCP update broke the resources folder that David created, will fix that asap.
Summary by Sourcery
Introduce a dedicated camera management tool with Cinemachine-aware support and shared screenshot handling, plus fix screenshot capture when the Screen Capture module is disabled and update docs/metadata.
New Features:
manage_cameraserver tool and Unity editor implementation for creating, configuring, and controlling Unity and Cinemachine cameras, including screenshots and multiview capture.camerasMCP resource that lists Unity and Cinemachine cameras along with Cinemachine Brain status.cameraCLI command group for camera operations, including creation, configuration, control, and screenshot capture.Bug Fixes:
ScreenCapture.CaptureScreenshotonly when available.Enhancements:
Build:
manage_cameratool andmanage_probuilderinmanifest.jsonand bump the package version to 9.5.2.Documentation:
manage_cameratool,camerasresource, and add a new 9.5.2 entry to the Recent Updates sections.Tests:
manage_cameraactions and parameter handling.Summary by CodeRabbit
Release Notes
New Features
Documentation