Skip to content

[Feature] manage_camera with cinemachine support#882

Merged
Scriptwonder merged 7 commits intoCoplayDev:betafrom
Scriptwonder:camera/cinemachine
Mar 7, 2026
Merged

[Feature] manage_camera with cinemachine support#882
Scriptwonder merged 7 commits intoCoplayDev:betafrom
Scriptwonder:camera/cinemachine

Conversation

@Scriptwonder
Copy link
Collaborator

@Scriptwonder Scriptwonder commented Mar 7, 2026

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

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Documentation update
  • Test update

Changes Made

New manage_camera Tool

  • Python server: camera.py command module with 16 actions — create cameras (with presets like follow, third_person, freelook, dolly, static, top_down, side_scroller), configure lens/body/aim/noise, set targets, manage priorities, blend settings, force/release camera overrides, and list cameras. Take the original camera module from manage_scene.py to this new camera.py (same for C# side)
  • C# Unity side: Split across ManageCamera.cs, CameraCreate.cs, CameraConfigure.cs, CameraControl.cs, and CameraHelpers.cs under Editor/Tools/Cameras/
  • Tiered Cinemachine support: Core actions always work with plain Unity Camera; Tier 1/2 actions gracefully fall back or error when Cinemachine isn't installed
  • New resource: mcpforunity://scene/cameras for listing cameras in the scene

Testing/Screenshots/Recordings

Documentation Updates

  • I have added/removed/modified tools or resources
  • If yes, I have updated all documentation files using:
    • The LLM prompt at tools/UPDATE_DOCS_PROMPT.md (recommended)
    • Manual updates following the guide at tools/UPDATE_DOCS.md

Related 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:

  • Add manage_camera server tool and Unity editor implementation for creating, configuring, and controlling Unity and Cinemachine cameras, including screenshots and multiview capture.
  • Expose a new cameras MCP resource that lists Unity and Cinemachine cameras along with Cinemachine Brain status.
  • Add a camera CLI command group for camera operations, including creation, configuration, control, and screenshot capture.

Bug Fixes:

  • Fix screenshot capture to work (and compile) when the Unity Screen Capture module is disabled by using reflection to call ScreenCapture.CaptureScreenshot only when available.

Enhancements:

  • Refactor screenshot parameter building and inline image extraction into shared utilities used by both scene and camera tools.
  • Extend the Unity tools window to expose manage-camera actions alongside manage-scene actions.

Build:

  • Register the new manage_camera tool and manage_probuilder in manifest.json and bump the package version to 9.5.2.

Documentation:

  • Update README and Chinese README to document the new manage_camera tool, cameras resource, and add a new 9.5.2 entry to the Recent Updates sections.

Tests:

  • Add integration tests for screenshot image extraction and new unit tests covering manage_camera actions and parameter handling.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added comprehensive camera management tool supporting both Unity Camera and Cinemachine with presets, priority control, and configurable pipelines.
    • Introduced cameras resource to list all available cameras in a scene.
    • Added support for camera blending, noise effects, and custom extensions.
    • Enabled screenshot capture through camera management system.
  • Documentation

    • Updated README with new manage_camera tool and cameras resource.

Copilot AI review requested due to automatic review settings March 7, 2026 06:49
@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Mar 7, 2026

Reviewer's Guide

Introduces a new cross-platform manage_camera tool and related Unity editor/Cinemachine infrastructure (including CLI commands and a cameras resource), refactors screenshot handling to be shared between scene and camera tools, and fixes ScreenCapture compile errors by using reflection-based detection and invocation.

Sequence diagram for manage_camera screenshot_multiview flow with shared screenshot utilities

sequenceDiagram
    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
Loading

Class diagram for new Unity camera tooling and resource

classDiagram
    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
Loading

File-Level Changes

Change Details Files
Refactor screenshot parameter handling and inline image extraction into shared utilities and update scene tool/tests to use them.
  • Removed inlined screenshot parameter coercion and image extraction logic from the scene tool and replaced it with calls to shared helpers.
  • Implemented extract_screenshot_images to translate Unity screenshot responses into ToolResult objects with text and image blocks, supporting single, batch, and contact-sheet outputs.
  • Implemented build_screenshot_params to validate and populate screenshot-related parameters (file name, super size, camera, includeImage, maxResolution, orbit/batch options, view transforms) for both scene and camera tools, including stricter numeric validation and error messages.
  • Updated manage_scene to call build_screenshot_params and extract_screenshot_images for screenshot actions and removed now-redundant imports and logic.
  • Adjusted screenshot-related integration tests to target the new helper functions and behavior (e.g., removal of the action guard in image extraction).
Server/src/services/tools/manage_scene.py
Server/src/services/tools/utils.py
Server/tests/integration/test_manage_scene_screenshot_params.py
Add reflection-based ScreenCapture handling in Unity to avoid compile errors when the Screen Capture module is disabled, while preserving async screenshot behavior and camera fallback.
  • Extended ScreenshotUtility with cached reflection metadata for ScreenCapture.CaptureScreenshot and tightened detection of the Screen Capture module using Type.GetType plus method lookup.
  • Replaced direct ScreenCapture.CaptureScreenshot calls (and UNITY_2022_1_OR_NEWER conditionals) with reflection-based invocation guarded by module availability, so projects compile even when com.unity.modules.screencapture is disabled.
  • Kept and clarified the camera-based fallback path for when ScreenCapture is unavailable, logging a warning message.
  • Removed the old pre-2022.1 compile-time #if branches since behavior is now determined at runtime via reflection.
MCPForUnity/Runtime/Helpers/ScreenshotUtility.cs
Introduce a full manage_camera tool stack (server, Unity editor, CLI, tests) to manage Unity cameras and Cinemachine virtual cameras, including presets, pipelines, blending, extensions, and screenshots.
  • Added a new manage_camera MCP tool on the server that normalizes actions, routes them to Unity, supports action category validation, and reuses the shared screenshot helpers for screenshot and screenshot_multiview actions, returning inline images when present.
  • Implemented a corresponding Unity editor tooling layer split into ManageCamera, CameraCreate, CameraConfigure, CameraControl, and CameraHelpers to handle basic Camera operations and Cinemachine-specific features when available, including presets, target/lens/priority configuration, pipeline components (Body/Aim/Noise), extensions, Brain setup/status, blending, and camera overrides.
  • Designed the tool with tiered behavior: Tier 1 actions (e.g., create_camera, set_target, set_lens, set_priority, list_cameras, screenshot) always work using plain UnityEngine.Camera, while Tier 2 actions require Cinemachine and return clear error messages with fallback hints if the package is missing.
  • Used SerializedObject and SerializedProperty to safely edit struct-based fields like Cinemachine lens and priority, avoiding persistence bugs and making the configuration robust across versions.
  • Implemented runtime detection of Cinemachine presence and types via UnityTypeResolver/reflection and helper accessors in CameraHelpers, including version reporting and Brain/camera lookup utilities.
  • Added rich camera listing via CameraControl.ListCameras, returning per-camera metadata (priority, live status, follow/lookAt targets, body/aim/noise types, extensions) plus Brain summary when Cinemachine is installed.
  • Provided robust error handling and logging, with ErrorResponse payloads and McpLog.Error logging on exceptions in Unity handlers.
  • Added a comprehensive Python test suite for manage_camera covering action sets, parameter routing, screenshot param scoping/validation, case-insensitive action names, and non-dict Unity responses.
Server/src/services/tools/manage_camera.py
MCPForUnity/Editor/Tools/Cameras/ManageCamera.cs
MCPForUnity/Editor/Tools/Cameras/CameraCreate.cs
MCPForUnity/Editor/Tools/Cameras/CameraConfigure.cs
MCPForUnity/Editor/Tools/Cameras/CameraControl.cs
MCPForUnity/Editor/Tools/Cameras/CameraHelpers.cs
Server/tests/test_manage_camera.py
MCPForUnity/Editor/Tools/Cameras.meta
MCPForUnity/Editor/Tools/Cameras/ManageCamera.cs.meta
MCPForUnity/Editor/Tools/Cameras/CameraCreate.cs.meta
MCPForUnity/Editor/Tools/Cameras/CameraConfigure.cs.meta
MCPForUnity/Editor/Tools/Cameras/CameraControl.cs.meta
MCPForUnity/Editor/Tools/Cameras/CameraHelpers.cs.meta
Expose cameras as an MCP resource and integrate the new camera tool into the CLI and editor UI.
  • Added a cameras MCP resource (mcpforunity://scene/cameras) on the server that calls a new Unity get_cameras command and parses it into MCPResponse, returning both Unity and Cinemachine cameras plus Brain state.
  • Implemented the Unity-side CamerasResource handler that delegates to CameraControl.ListCameras to serve get_cameras requests.
  • Hooked the manage_camera CLI command group into the Python CLI, with subcommands for setup, creation, configuration, extensions, control, and capture; each builds the appropriate payload (including normalization of top-level vs properties keys) and calls the manage_camera server tool.
  • Updated the Unity editor McpToolsSection to treat manage_camera like manage_scene for UI affordances (using a shared action-row creator) by adding an IsManageCameraTool predicate.
  • Registered the new manage_camera tool and manage_probuilder in manifest.json so they are discoverable by MCP clients.
Server/src/services/resources/cameras.py
MCPForUnity/Editor/Resources/Scene/CamerasResource.cs
MCPForUnity/Editor/Resources/Scene/CamerasResource.cs.meta
Server/src/cli/main.py
Server/src/cli/commands/camera.py
MCPForUnity/Editor/Windows/Components/Tools/McpToolsSection.cs
manifest.json
Update README, localized docs, and manifest metadata to reflect the new version, manage_camera tool, and cameras resource.
  • Extended tools/UPDATE_DOCS_PROMPT.md with explicit instructions for maintaining the README “Recent Updates” sections in English and Chinese and keeping manifest.json in sync with version changes.
  • Bumped the manifest version from 9.4.8 to 9.5.2 and documented the new release in both README files, including a short summary of manage_camera, Cinemachine support, camera resource, and the priority persistence fix.
  • Updated the list of available tools and resources in README and README-zh to include manage_camera in the tools list and cameras in the resources list, adjusting ordering to keep them consistent.
  • Moved the previous top release entry into the “Older releases” block as per the rotation rule.
tools/UPDATE_DOCS_PROMPT.md
README.md
docs/i18n/README-zh.md
manifest.json

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 7, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d138d00d-dd58-4e31-be62-0014c0faf4d7

📥 Commits

Reviewing files that changed from the base of the PR and between 1d623ec and f2b9bb3.

⛔ Files ignored due to path filters (1)
  • Server/uv.lock is excluded by !**/*.lock
📒 Files selected for processing (27)
  • MCPForUnity/Editor/Resources/Scene/CamerasResource.cs
  • MCPForUnity/Editor/Resources/Scene/CamerasResource.cs.meta
  • MCPForUnity/Editor/Tools/Cameras.meta
  • MCPForUnity/Editor/Tools/Cameras/CameraConfigure.cs
  • MCPForUnity/Editor/Tools/Cameras/CameraConfigure.cs.meta
  • MCPForUnity/Editor/Tools/Cameras/CameraControl.cs
  • MCPForUnity/Editor/Tools/Cameras/CameraControl.cs.meta
  • MCPForUnity/Editor/Tools/Cameras/CameraCreate.cs
  • MCPForUnity/Editor/Tools/Cameras/CameraCreate.cs.meta
  • MCPForUnity/Editor/Tools/Cameras/CameraHelpers.cs
  • MCPForUnity/Editor/Tools/Cameras/CameraHelpers.cs.meta
  • MCPForUnity/Editor/Tools/Cameras/ManageCamera.cs
  • MCPForUnity/Editor/Tools/Cameras/ManageCamera.cs.meta
  • MCPForUnity/Editor/Windows/Components/Tools/McpToolsSection.cs
  • MCPForUnity/Runtime/Helpers/ScreenshotUtility.cs
  • README.md
  • Server/src/cli/commands/camera.py
  • Server/src/cli/main.py
  • Server/src/services/resources/cameras.py
  • Server/src/services/tools/manage_camera.py
  • Server/src/services/tools/manage_scene.py
  • Server/src/services/tools/utils.py
  • Server/tests/integration/test_manage_scene_screenshot_params.py
  • Server/tests/test_manage_camera.py
  • docs/i18n/README-zh.md
  • manifest.json
  • tools/UPDATE_DOCS_PROMPT.md

📝 Walkthrough

Walkthrough

Adds 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

Cohort / File(s) Summary
Cameras Resource
MCPForUnity/Editor/Resources/Scene/CamerasResource.cs, MCPForUnity/Editor/Resources/Scene/CamerasResource.cs.meta
New CamerasResource.HandleCommand exposes get_cameras, delegates to CameraControl.ListCameras, with try/catch and ErrorResponse on failure.
Camera Tools — Helpers
MCPForUnity/Editor/Tools/Cameras/CameraHelpers.cs, MCPForUnity/Editor/Tools/Cameras/CameraHelpers.cs.meta, MCPForUnity/Editor/Tools/Cameras/Cameras.meta
New Cinemachine detection, type resolution, object/component resolution and reflection/SerializedObject utilities used by camera tooling.
Camera Tools — Control
MCPForUnity/Editor/Tools/Cameras/CameraControl.cs, .../CameraControl.cs.meta
Implements camera enumeration, brain status, blend config, force/release overrides, and internal override tracking (_overrideId).
Camera Tools — Configuration
MCPForUnity/Editor/Tools/Cameras/CameraConfigure.cs, .../CameraConfigure.cs.meta
Adds many configuration APIs for basic and Cinemachine cameras (targets, lens, priority, body/aim/noise, extension add/remove) using SerializedObject, reflection, Undo and MarkDirty.
Camera Tools — Creation
MCPForUnity/Editor/Tools/Cameras/CameraCreate.cs, .../CameraCreate.cs.meta
Adds creation helpers for basic and Cinemachine cameras, presets mapping, and EnsureBrain to add/configure a CinemachineBrain.
Command Dispatcher
MCPForUnity/Editor/Tools/Cameras/ManageCamera.cs, .../ManageCamera.cs.meta
Public ManageCamera.HandleCommand routes actions (tiered by Cinemachine availability) to create/configure/control helpers and screenshots, with error handling.
Editor UI Integration
MCPForUnity/Editor/Windows/Components/Tools/McpToolsSection.cs
Expands UI condition to show manage actions for manage_camera tools similar to manage_scene.
Runtime Screenshot Reflection
MCPForUnity/Runtime/Helpers/ScreenshotUtility.cs
Uses reflection to discover/invoke ScreenCapture.CaptureScreenshot across modules, caches MethodInfo, and unifies fallback to camera-based capture.
Python CLI
Server/src/cli/commands/camera.py, Server/src/cli/main.py
Adds Click-based camera commands (ping, list, create, ensure-brain, set-*, add/remove-extension, set-blend, force/release, screenshot[s]) and registers camera as an optional CLI module.
Python Server Tool
Server/src/services/tools/manage_camera.py
Adds manage_camera async tool: validates actions, builds params (including screenshot params), dispatches to Unity, and extracts inline images when present.
Python Resource
Server/src/services/resources/cameras.py
Adds MCP resource endpoint get_cameras that sends get_cameras to Unity and returns parsed MCPResponse.
Screenshot Utilities
Server/src/services/tools/utils.py
New build_screenshot_params to validate/assemble screenshot params and extract_screenshot_images to parse inline base64 images from Unity responses.
ManageScene refactor & tests
Server/src/services/tools/manage_scene.py, Server/tests/integration/test_manage_scene_screenshot_params.py, Server/tests/test_manage_camera.py
Centralizes screenshot param handling (uses build_screenshot_params), replaces internal extractor with extract_screenshot_images, and adds comprehensive manage_camera tests.
Docs & Manifest
README.md, docs/i18n/README-zh.md, manifest.json, tools/UPDATE_DOCS_PROMPT.md
Adds v9.5.2 (beta) notes, documents manage_camera and cameras resource, updates manifest and docs prompt rules.

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
Loading
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
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

codex

Suggested reviewers

  • dsarno
  • justinpbarnett

Poem

🐰 I hopped through scenes and found a view so bright,
I set the lens, swapped bodies, nudged the blend just right,
Presets and noise, a Cinemachine dance,
Snapshots captured in a single glance,
The rabbit cheers — cameras now take flight! 📸✨

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • 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.
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>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@Scriptwonder Scriptwonder merged commit 241118d into CoplayDev:beta Mar 7, 2026
1 check passed
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_camera Python tool and C# handler with 18 actions (setup, create, configure, extend, control, capture), split across ManageCamera.cs, CameraHelpers.cs, CameraCreate.cs, CameraControl.cs, and CameraConfigure.cs
  • Screenshot handling logic extracted from manage_scene.py into shared utilities (build_screenshot_params, extract_screenshot_images) in utils.py, consumed by both manage_scene and manage_camera
  • Bug fix: ScreenshotUtility.cs uses reflection to call ScreenCapture.CaptureScreenshot so 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
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
from typing import Optional, Any
from typing import Any

Copilot uses AI. Check for mistakes.
from typing import Optional, Any

from cli.utils.config import get_config
from cli.utils.output import format_output, print_error, print_success
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
from cli.utils.output import format_output, print_error, print_success
from cli.utils.output import format_output

Copilot uses AI. Check for mistakes.
catch (Exception ex)
{
McpLog.Error($"[ManageCamera] Action '{action}' failed: {ex}");
return new ErrorResponse($"Error in action '{action}': {ex.Message}");
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 }).

Suggested change
return new ErrorResponse($"Error in action '{action}': {ex.Message}");
return new ErrorResponse($"Error in action '{action}': {ex.Message}", new { stackTrace = ex.StackTrace });

Copilot uses AI. Check for mistakes.
}

if (IsManageSceneTool(tool))
if (IsManageSceneTool(tool) || IsManageCameraTool(tool))
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
if (IsManageSceneTool(tool) || IsManageCameraTool(tool))
if (IsManageSceneTool(tool))

Copilot uses AI. Check for mistakes.
@coderabbitai coderabbitai bot mentioned this pull request Mar 8, 2026
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants