Skip to content

Conversation

dsarno
Copy link
Owner

@dsarno dsarno commented Aug 19, 2025

Summary by CodeRabbit

  • New Features

    • Added macOS-specific config support (incl. Claude Desktop), optional auto-management, and a manual setup guide.
    • Introduced safer, transactional script editing with validation, structured operations, atomic writes, and debounced refresh.
    • Added project root discovery action.
    • Implemented framed socket transport with handshake for more reliable communication.
    • Exposed resource browsing/reading for Unity C# assets and wrapper tools for clients lacking resource primitives.
    • Improved port discovery with multi-source scanning and validation.
  • Chores

    • Logging overhauled; reduced stdio noise; BOM-free JSON writes with validation.
  • Tests

    • Added extensive framing, script tools, editing, logging, and resources test suites.
  • Style

    • Minor formatting cleanup.

dsarno added 30 commits August 14, 2025 22:37
…ove blob stream tools; simplify tool registration

- Python server: always consume handshake and negotiate framing on reconnects (prevents invalid framed length).\n- C#: strict FRAMING=1 handshake and NoDelay; debounce AssetDatabase/compilation.\n- Tools: keep manage_script + script edits; remove manage_script_stream and test tools from default registration.\n- Editor window: guard against auto retargeting IDE config.
…Exact, safe write framing; remove unused vars
… MCP edit ops; mitigate false 'no opening brace' errors and allow relaxed validation for text edits
…ority and server apply_text_edits/validate; add resources list/read; deprecate manage_script read/update/edit; remove stdout prints; tweak connection handshake logging
Add initial transport handshake tests with plan placeholders
dsarno added 9 commits August 17, 2025 17:34
…ests

Convert skip decorators to xfail and harden framing tests
…-logging

Add handshake fallback and logging checks
…ck; add uv -q for quieter stdio; MCP server: compatibility guards for capabilities/resource decorators and indentation fix; ManageScript: shadow var fix; robust mac config path.
…text edits; anchor aliasing and text-op conversion; immediate compile on NL/structured; add resource_tools (tail_lines, find_in_file); update test cases
…-response

Fix ApplyTextEdits replacement index calculation and port probe handshake
Copy link

coderabbitai bot commented Aug 19, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Adds macOS config path support for Claude Desktop, introduces a new ManageEditor get_project_root action, significantly expands ManageScript with safe path resolution, edit/validate actions, and debounced refresh, enforces strict framed I/O in the Unity bridge and Python client, adds resource APIs and tool registrations, and introduces comprehensive tests and configs.

Changes

Cohort / File(s) Summary
Model and data updates
UnityMcpBridge/Editor/Models/McpClient.cs, UnityMcpBridge/Editor/Data/McpClients.cs
Adds public macConfigPath to McpClient and populates it for Claude Desktop on macOS.
Editor command additions
UnityMcpBridge/Editor/Tools/ManageEditor.cs
Adds get_project_root action with path normalization and error handling; updates dispatch and messages.
Script management overhaul
UnityMcpBridge/Editor/Tools/ManageScript.cs
Introduces safe Assets/ path resolution, apply_text_edits, validate, edit actions, atomic I/O, debounced refresh, Roslyn-enabled validation (conditional), helpers/utilities, and public refresh helpers. Deprecates full update path.
Framed transport in Unity editor
UnityMcpBridge/Editor/UnityMcpBridge.cs
Enforces framed I/O with 8-byte header, size/time limits, handshake message, and timeout-aware read/write helpers; replaces legacy stream handling.
Editor window config handling
UnityMcpBridge/Editor/Windows/UnityMcpEditorWindow.cs
Writes BOM-free JSON atomically, adds quiet flag to args, splits macOS/Linux config logic, mirrors macOS config to Linux-style path when needed, adds auto-manage flag and manual instruction window.
Python port discovery and framing probe
UnityMcpBridge/UnityMcpServer~/src/port_discovery.py
Adds framing-aware probe, registry scanning, defaults/constants, and discovery helpers; prefers latest responsive port.
Server logging and resources API
UnityMcpBridge/UnityMcpServer~/src/server.py
Replaces stdout logging with structured logger and rotating file handler; adds capabilities guard and resource list/read endpoints scoped to project/Assets.
Server tool registry
UnityMcpBridge/UnityMcpServer~/src/tools/__init__.py, .../manage_asset.py
Registers manage_script_edits first; adds resource tool registration; switches to logger; formatting newline in manage_asset.
Script tools (client-side Python)
UnityMcpBridge/UnityMcpServer~/src/tools/manage_script.py
Adds apply_text_edits, create_script, delete_script, validate_script tools; URI parsing helper; deprecates update; handles encoded contents in requests/responses.
Natural-language/script edit tooling
UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py
New module enabling structured and NL-driven edits with local preview/diff, precondition hashing, and routing to Unity manage_script.
Resource wrapper tools
UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py
New module providing list/read/find tools with safe project-root resolution and URI-to-path translation.
Python Unity connection framing
UnityMcpBridge/UnityMcpServer~/src/unity_connection.py
Adds FRAMING=1 handshake, per-connection I/O lock, framed send/receive, exact-read helper, retry helpers (sync/async), and connection lifecycle adjustments.
Configs and tests
UnityMcpBridge/UnityMcpServer~/src/pyrightconfig.json, tests/test_logging_stdout.py, tests/test_resources_api.py, tests/test_script_editing.py, tests/test_script_tools.py, tests/test_transport_framing.py, test_unity_socket_framing.py
Adds Pyright config; tests for logging (no stdout), framing behavior, script tools and editing (xfail stubs), resources API (xfail stubs), and a manual framing client script.

Sequence Diagram(s)

sequenceDiagram
  participant Client as MCP Client (Python)
  participant Conn as UnityConnection
  participant Unity as UnityMcpBridge (Editor)

  Client->>Conn: connect()
  Conn->>Unity: TCP connect
  Unity-->>Conn: "WELCOME UNITY-MCP 1 FRAMING=1"
  Conn->>Conn: enable framing
  Client->>Conn: send_command_with_retry(type, params)
  Conn->>Unity: [8-byte len][JSON]
  Unity-->>Conn: [8-byte len][JSON response]
  Conn-->>Client: parsed response
Loading
sequenceDiagram
  participant Tool as script_apply_edits (server)
  participant UTools as manage_script tools
  participant Unity as ManageScript.cs
  participant Editor as Unity Editor

  Tool->>UTools: apply_text_edits(uri, edits, precondition)
  UTools->>Unity: action=apply_text_edits (framed)
  Unity->>Editor: validate, apply, atomic write, schedule refresh
  Unity-->>UTools: {success, sha256, uri}
  UTools-->>Tool: forwarded response
Loading
sequenceDiagram
  participant Client as MCP Client
  participant RTools as resource_tools
  participant UEdit as ManageEditor.cs

  Client->>RTools: list_resources(project=auto)
  RTools->>UEdit: command get_project_root
  UEdit-->>RTools: {projectRoot}
  RTools->>RTools: resolve safe paths, glob *.cs under Assets
  RTools-->>Client: {uris, count}
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

Suggested labels

codex

Poem

A rabbit taps frames, eight bytes at a hop,
Scripts snip-snip safely, with a debounced stop.
Roots found, paths bound, resources in sight,
Quiet logs burrow, no stdout tonight.
With paws on the wire and edits that sing—
Unity and MCP dance in a ring. 🐇✨

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 14a6cba and 14805f0.

📒 Files selected for processing (21)
  • UnityMcpBridge/Editor/Data/McpClients.cs (1 hunks)
  • UnityMcpBridge/Editor/Models/McpClient.cs (1 hunks)
  • UnityMcpBridge/Editor/Tools/ManageEditor.cs (4 hunks)
  • UnityMcpBridge/Editor/Tools/ManageScript.cs (11 hunks)
  • UnityMcpBridge/Editor/UnityMcpBridge.cs (5 hunks)
  • UnityMcpBridge/Editor/Windows/UnityMcpEditorWindow.cs (8 hunks)
  • UnityMcpBridge/UnityMcpServer~/src/port_discovery.py (2 hunks)
  • UnityMcpBridge/UnityMcpServer~/src/pyrightconfig.json (1 hunks)
  • UnityMcpBridge/UnityMcpServer~/src/server.py (2 hunks)
  • UnityMcpBridge/UnityMcpServer~/src/tools/__init__.py (3 hunks)
  • UnityMcpBridge/UnityMcpServer~/src/tools/manage_asset.py (1 hunks)
  • UnityMcpBridge/UnityMcpServer~/src/tools/manage_script.py (3 hunks)
  • UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py (1 hunks)
  • UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py (1 hunks)
  • UnityMcpBridge/UnityMcpServer~/src/unity_connection.py (7 hunks)
  • test_unity_socket_framing.py (1 hunks)
  • tests/test_logging_stdout.py (1 hunks)
  • tests/test_resources_api.py (1 hunks)
  • tests/test_script_editing.py (1 hunks)
  • tests/test_script_tools.py (1 hunks)
  • tests/test_transport_framing.py (1 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch protocol-framing

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@dsarno dsarno closed this Aug 19, 2025
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Greptile Summary

This PR implements a comprehensive protocol framing upgrade for the Unity MCP (Model Context Protocol) bridge system. The changes introduce a new binary framing protocol that replaces the previous text-based communication with 8-byte big-endian length headers for message boundaries. This addresses fundamental reliability issues where JSON parsing could fail with partial or malformed messages.

Key architectural changes include:

Protocol Layer: The core Unity-MCP TCP communication now uses strict framing with mandatory handshake (FRAMING=1) and timeout-aware I/O operations. All messages are prefixed with their exact length, eliminating message boundary ambiguity.

Script Management: Major refactoring of script editing capabilities with new granular tools (apply_text_edits, create_script, delete_script, validate_script) that support incremental editing rather than full-file replacement. This includes SHA256 precondition checking for concurrent modification protection and atomic file operations.

Cross-Platform Support: Enhanced macOS compatibility with proper configuration path handling for Claude Desktop and other MCP clients.

Resource Management: Addition of MCP resources API that allows AI assistants to discover and read Unity C# scripts directly through the protocol, with proper path sandboxing and security controls.

Logging Infrastructure: Comprehensive logging overhaul that ensures stdout remains clean for MCP protocol communication, with all diagnostic output redirected to stderr and optional file logging.

The changes maintain backward compatibility where possible while establishing a foundation for more reliable MCP communication. The new framed protocol supports large payload transfers (up to 64MB) with proper flow control and prevents the connection issues that could occur with the previous implementation.

Important Files Changed

File Changes Overview
Filename Score Overview
UnityMcpBridge/Editor/UnityMcpBridge.cs 4/5 Implements strict binary protocol framing with 8-byte headers and mandatory handshake
UnityMcpBridge/Editor/Tools/ManageScript.cs 4/5 Major refactor adding transactional text editing, security hardening, and AST-based operations
UnityMcpBridge/UnityMcpServer~/src/unity_connection.py 3/5 Introduces framed communication with thread-safe I/O and handshake validation
UnityMcpBridge/UnityMcpServer~/src/server.py 4/5 Adds MCP resources API and strict logging configuration for protocol compliance
UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py 4/5 New advanced script editing tool with natural language parsing and structured operations
UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py 2/5 Resource wrapper tools with potential security vulnerabilities in path handling
UnityMcpBridge/Editor/Windows/UnityMcpEditorWindow.cs 4/5 Adds UV quiet flag and UTF-8 BOM handling to prevent protocol interference
UnityMcpBridge/UnityMcpServer~/src/tools/manage_script.py 4/5 Refactors to granular tools and deprecates monolithic update operations
UnityMcpBridge/UnityMcpServer~/src/port_discovery.py 4/5 Implements framing detection in port discovery with protocol negotiation
UnityMcpBridge/UnityMcpServer~/src/tools/__init__.py 3/5 Updates tool registration with logging and new module imports
test_unity_socket_framing.py 4/5 New comprehensive socket framing test with large payload validation
tests/test_transport_framing.py 4/5 Transport layer framing tests with handshake and protocol enforcement
tests/test_script_tools.py 4/5 Comprehensive script management testing with MCP dependency mocking
tests/test_script_editing.py 5/5 Test framework stubs for script editing safety and performance features
tests/test_logging_stdout.py 4/5 AST-based validation ensuring no stdout contamination in server code
tests/test_resources_api.py 4/5 Security-focused test stubs for resource API path validation
UnityMcpBridge/Editor/Tools/ManageEditor.cs 4/5 Adds get_project_root command for external tool navigation
UnityMcpBridge/Editor/Data/McpClients.cs 5/5 Adds macOS configuration path for Claude Desktop cross-platform support
UnityMcpBridge/Editor/Models/McpClient.cs 5/5 Adds macOS configuration path field to model definition
UnityMcpBridge/UnityMcpServer~/src/tools/manage_asset.py 5/5 Trivial newline addition for POSIX compliance
UnityMcpBridge/UnityMcpServer~/src/pyrightconfig.json 5/5 Python Language Server configuration for improved development experience

Confidence score: 3/5

  • This PR introduces significant architectural changes that improve protocol reliability but includes complex logic that could introduce subtle bugs
  • Score reflects the extensive scope of changes across critical communication pathways and the introduction of new security-sensitive path handling logic
  • Pay close attention to UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py for path traversal vulnerabilities and unity_connection.py for handshake timeout edge cases

Sequence Diagram

sequenceDiagram
    participant User
Loading

21 files reviewed, 13 comments

Edit Code Review Bot Settings | Greptile

string commandText = null;
bool usedFraming = true;

if (true)
Copy link

Choose a reason for hiding this comment

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

style: Dead code: if (true) condition makes the branch always execute and usedFraming variable is always true

Suggested change
if (true)
// Enforced framed mode for this connection
commandText = await ReadFrameAsUtf8Async(stream, FrameIOTimeoutMs);

{
throw new System.IO.IOException("Read timed out");
}
int r = readTask.Result;
Copy link

Choose a reason for hiding this comment

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

logic: Potential race condition: accessing readTask.Result without checking if the task completed successfully could throw if the read task faulted

stderr_handler = logging.StreamHandler(stream=sys.stderr)
stderr_handler.setFormatter(logging.Formatter(config.log_format))

handlers = [stderr_handler]
Copy link

Choose a reason for hiding this comment

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

style: handlers variable is defined but never used

Suggested change
handlers = [stderr_handler]
stderr_handler = logging.StreamHandler(stream=sys.stderr)
stderr_handler.setFormatter(logging.Formatter(config.log_format))

# Read a small bounded amount looking for pong
chunks = []
total = 0
data = b""
Copy link

Choose a reason for hiding this comment

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

style: variable data is initialized but immediately overwritten in the loop - this initialization is redundant

PROJECT_ROOT = Path(os.environ.get("UNITY_PROJECT_ROOT", Path.cwd())).resolve()
ASSETS_ROOT = (PROJECT_ROOT / "Assets").resolve()

def _resolve_safe_path_from_uri(uri: str) -> Path | None:
Copy link

Choose a reason for hiding this comment

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

style: Union type syntax Path | None requires Python 3.10+, consider Optional[Path] for compatibility

Comment on lines +104 to +105
if payload_len == 0:
raise Exception("Invalid framed length: 0")
Copy link

Choose a reason for hiding this comment

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

style: Zero-length payload rejection may be overly strict - some protocols allow zero-length messages as keepalives or control messages

Comment on lines +233 to +235
header = struct.pack('>Q', len(payload))
self.sock.sendall(header)
self.sock.sendall(payload)
Copy link

Choose a reason for hiding this comment

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

style: Sending header and payload in separate sendall() calls could cause partial writes in edge cases - consider combining into single send

Comment on lines +57 to +58
elif uri.startswith("file://"):
raw = uri[len("file://"):]
Copy link

Choose a reason for hiding this comment

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

logic: Potential path traversal vulnerability with file:// URIs - they bypass the unity://path/ prefix validation and could reference arbitrary filesystem paths

window = int(m.group(1))
method = m.group(2)
# naive search for method header to get a line number
text_all = p.read_text(encoding="utf-8")
Copy link

Choose a reason for hiding this comment

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

style: Reading entire file content twice (here and later) is inefficient for large files - consider reading once and reusing

- ignore_case: case-insensitive by default
- max_results: cap results to avoid huge payloads
"""
import re
Copy link

Choose a reason for hiding this comment

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

syntax: Redundant import re statement since re is already imported at module level

Suggested change
import re
try:

@dsarno dsarno deleted the protocol-framing branch August 28, 2025 01:44
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.

1 participant