Skip to content

Add rack device introspection: get_rack_device_info tool + chain summaries in get_track_info#67

Open
BenCello wants to merge 1 commit intoahujasid:mainfrom
BenCello:main
Open

Add rack device introspection: get_rack_device_info tool + chain summaries in get_track_info#67
BenCello wants to merge 1 commit intoahujasid:mainfrom
BenCello:main

Conversation

@BenCello
Copy link
Copy Markdown

@BenCello BenCello commented Feb 13, 2026

get_track_info now reports chain names and device counts for rack devices. New get_rack_device_info endpoint drills into a specific rack to list all nested devices per chain, with recursive serialization for nested racks.

Co-Authored-By: Claude Opus 4.6

Summary by CodeRabbit

  • New Features
    • Added ability to query and retrieve detailed rack device information, including nested chains and their configurations from Ableton tracks.

…aries in get_track_info

get_track_info now reports chain names and device counts for rack devices.
New get_rack_device_info endpoint drills into a specific rack to list all
nested devices per chain, with recursive serialization for nested racks.

Co-Authored-By: Claude Opus 4.6
@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Add rack device introspection with chain details

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add get_rack_device_info tool for detailed rack device introspection
• Enhance get_track_info with chain summaries for rack devices
• Implement recursive device serialization for nested racks
• Support drilling into specific rack devices to list all chains
Diagram
flowchart LR
  A["get_track_info"] -->|enhanced| B["Device Info with Chains"]
  C["get_rack_device_info"] -->|new tool| D["Rack Device Details"]
  D -->|recursive| E["Nested Devices per Chain"]
  B -->|chains summary| F["Chain Names & Device Counts"]
Loading

Grey Divider

File Changes

1. AbletonMCP_Remote_Script/__init__.py ✨ Enhancement +56/-2

Implement rack device introspection with recursive serialization

• Added _get_rack_device_info method to retrieve detailed rack device information with chains and
 nested devices
• Implemented _serialize_device helper method for recursive serialization of devices and their
 chains
• Enhanced _get_track_info to include chain information (index, name, device_count) for rack
 devices
• Added command routing for new get_rack_device_info endpoint with track and device index
 parameters

AbletonMCP_Remote_Script/init.py


2. MCP_Server/server.py ✨ Enhancement +17/-0

Add get_rack_device_info MCP tool endpoint

• Added new get_rack_device_info MCP tool for querying rack device chains and nested devices
• Tool accepts track_index and device_index parameters to target specific rack devices
• Includes error handling and JSON response formatting consistent with existing tools

MCP_Server/server.py


Grey Divider

Qodo Logo

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 13, 2026

📝 Walkthrough

Walkthrough

This pull request adds support for querying detailed rack device information in Ableton Live. It introduces a new command get_rack_device_info that recursively serializes nested chains and devices, exposing this functionality through the MCP server while enhancing the remote script with appropriate error handling and serialization methods.

Changes

Cohort / File(s) Summary
Remote Script Rack Device Support
AbletonMCP_Remote_Script/__init__.py
Added _get_rack_device_info() and _serialize_device() methods to retrieve and recursively serialize rack device information. Enhanced _get_track_info() to include chains metadata for devices. Includes error handling and validation.
MCP Server Tool Exposure
MCP_Server/server.py
Added public tool function get_rack_device_info() to expose rack device querying via MCP. Function appears twice in file (duplicate definition), returning pretty-printed JSON with error handling.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant MCP_Server as MCP Server
    participant RemoteScript as Remote Script
    participant Ableton as Ableton Live

    Client->>MCP_Server: get_rack_device_info(track_index, device_index)
    MCP_Server->>RemoteScript: _process_command(get_rack_device_info, ...)
    RemoteScript->>RemoteScript: _get_rack_device_info(track_index, device_index)
    RemoteScript->>Ableton: Query track and device objects
    Ableton-->>RemoteScript: Device and chain data
    RemoteScript->>RemoteScript: _serialize_device() recursively
    RemoteScript-->>MCP_Server: Serialized device structure
    MCP_Server->>MCP_Server: Format as JSON
    MCP_Server-->>Client: Pretty-printed JSON response
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Note: While the remote script additions are straightforward, the duplicate get_rack_device_info() definition in server.py warrants careful attention during review to determine if this is intentional or an error requiring correction.

Poem

🐰 Hop, hop—the chains now dance,
Each nested device caught in our glance,
Recursive trees of Ableton delight,
Rack devices queried—structured just right! 🎛️

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the two main changes: adding a new get_rack_device_info tool and including chain summaries in get_track_info, matching the changeset content.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

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

No actionable comments were generated in the recent review. 🎉

🧹 Recent nitpick comments
AbletonMCP_Remote_Script/__init__.py (1)

428-445: Consider adding a device_index to the serialized chain devices and a recursion depth guard.

Two suggestions:

  1. Missing index on nested devices: _get_track_info (line 397) includes an "index" field for each device, but _serialize_device omits it for devices within chains. This makes it harder for consumers to reference a specific nested device in subsequent calls.

  2. No recursion depth limit: While Ableton practically limits rack nesting, adding a depth guard would prevent a RecursionError from propagating unexpectedly.

♻️ Proposed changes
-    def _serialize_device(self, device):
+    def _serialize_device(self, device, max_depth=10, _current_depth=0):
         """Serialize a device, recursively including chains for rack devices"""
         device_info = {
             "name": device.name,
             "class_name": device.class_name,
             "type": self._get_device_type(device)
         }
-        if device.can_have_chains:
+        if device.can_have_chains and _current_depth < max_depth:
             chains = []
             for chain_index, chain in enumerate(device.chains):
-                chain_devices = [self._serialize_device(dev) for dev in chain.devices]
+                chain_devices = [
+                    self._serialize_device(dev, max_depth, _current_depth + 1)
+                    for dev_index, dev in enumerate(chain.devices)
+                ]
+                for i, cd in enumerate(chain_devices):
+                    cd["index"] = i
                 chains.append({
                     "index": chain_index,
                     "name": chain.name,
                     "devices": chain_devices
                 })
             device_info["chains"] = chains
         return device_info

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


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.

@qodo-code-review
Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (2) 📎 Requirement gaps (0)

Grey Divider


Action required

1. IndexError breaks client loop 📘 Rule violation ⛯ Reliability
Description
The new rack introspection command raises IndexError for invalid indices, and the client handler
treats non-ValueError exceptions as serious and breaks the connection. This makes simple bad input
an availability/reliability issue instead of a handled edge case.
Code

AbletonMCP_Remote_Script/init.py[R450-457]

+            if track_index < 0 or track_index >= len(self._song.tracks):
+                raise IndexError("Track index out of range")
+
+            track = self._song.tracks[track_index]
+
+            if device_index < 0 or device_index >= len(track.devices):
+                raise IndexError("Device index out of range")
+
Evidence
Robust edge-case handling requires invalid inputs to be handled gracefully. The new code raises
IndexError, and existing client handling breaks the loop on exceptions that are not ValueError,
causing disconnects on out-of-range indices.

Rule 3: Generic: Robust Error Handling and Edge Case Management
AbletonMCP_Remote_Script/init.py[450-457]
AbletonMCP_Remote_Script/init.py[198-200]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Out-of-range indices currently raise `IndexError`, which leads the client handler to break the loop and disconnect.

## Issue Context
The client handler only treats `ValueError` as non-fatal; other exceptions trigger a disconnect.

## Fix Focus Areas
- AbletonMCP_Remote_Script/__init__.py[450-457]
- AbletonMCP_Remote_Script/__init__.py[198-200]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Exception exposes device.name 📘 Rule violation ⛨ Security
Description
The new rack endpoint includes device.name in an exception message, and error handling sends
str(e) back to the client. This can leak internal session/device details to the caller.
Code

AbletonMCP_Remote_Script/init.py[R460-462]

+            if not device.can_have_chains:
+                raise ValueError("Device '{}' is not a rack and does not have chains".format(device.name))
+
Evidence
Secure error handling requires user-facing messages to avoid internal details. The new code embeds
the rack device name in the exception, and the server sends exception strings back to clients as the
error message.

Rule 4: Generic: Secure Error Handling
AbletonMCP_Remote_Script/init.py[460-462]
AbletonMCP_Remote_Script/init.py[184-187]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The error message includes `device.name` and is propagated to clients via `str(e)`.

## Issue Context
User-facing error responses should be generic and not reveal internal session/device details.

## Fix Focus Areas
- AbletonMCP_Remote_Script/__init__.py[460-462]
- AbletonMCP_Remote_Script/__init__.py[184-187]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Unbounded rack serialization 🐞 Bug ⛯ Reliability
Description
New rack serialization recursively walks all nested racks/chains with no depth/size limits, so
deep/large racks can cause very slow responses, huge payloads, or a Python RecursionError. Large
payloads also increase the chance the Remote Script’s blocking sendall (no timeout) will stall a
client handler thread if the client is slow/disconnected.
Code

AbletonMCP_Remote_Script/init.py[R428-445]

+    def _serialize_device(self, device):
+        """Serialize a device, recursively including chains for rack devices"""
+        device_info = {
+            "name": device.name,
+            "class_name": device.class_name,
+            "type": self._get_device_type(device)
+        }
+        if device.can_have_chains:
+            chains = []
+            for chain_index, chain in enumerate(device.chains):
+                chain_devices = [self._serialize_device(dev) for dev in chain.devices]
+                chains.append({
+                    "index": chain_index,
+                    "name": chain.name,
+                    "devices": chain_devices
+                })
+            device_info["chains"] = chains
+        return device_info
Evidence
_serialize_device recurses for every device in every chain without any guard (depth/max devices),
and get_rack_device_info returns this full structure. The client handler socket has no timeout and
uses sendall, so a very large JSON response can block indefinitely under backpressure.

AbletonMCP_Remote_Script/init.py[428-469]
AbletonMCP_Remote_Script/init.py[133-177]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`get_rack_device_info` recursively serializes nested racks without any depth/size limits. Deep or large racks can produce huge responses, hit Python recursion limits, and/or cause long blocking socket sends.

### Issue Context
This endpoint is designed to “drill in” and may be called on complex Ableton projects where nested racks/chains can be large.

### Fix Focus Areas
- AbletonMCP_Remote_Script/__init__.py[428-469]
- AbletonMCP_Remote_Script/__init__.py[133-177]

### Suggested changes
- Update `_serialize_device(device, depth=0, max_depth=..., budget=...)`:
 - Stop recursing past `max_depth` and/or when a `max_total_devices` budget is exceeded.
 - Include a field like `&quot;truncated&quot;: true` or `&quot;truncation_reason&quot;: &quot;max_depth&quot;` when limits are reached.
 - Optionally include `index` values for devices within each chain to make truncated results still navigable.
- Update `_get_rack_device_info` to accept optional params (e.g., `max_depth`, `max_total_devices`) from `params` and pass them through.
- Consider making the client handler safer for large responses:
 - Set a reasonable socket timeout for sends, or
 - Send in chunks and abort cleanly if the client disconnects / blocks too long.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

4. Large JSON parsing cost 🐞 Bug ➹ Performance
Description
The new rack endpoint can return much larger JSON than existing calls, increasing the chance of
timeouts/CPU spikes in the MCP server’s receive loop which repeatedly re-parses the full accumulated
buffer to detect JSON completeness. This is a pre-existing design, but the new endpoint makes it
more likely to hit the worst case.
Code

MCP_Server/server.py[R287-302]

+@mcp.tool()
+def get_rack_device_info(ctx: Context, track_index: int, device_index: int) -> str:
+    """
+    Get detailed information about a rack device's chains and nested devices.
+
+    Parameters:
+    - track_index: The index of the track containing the rack device
+    - device_index: The index of the device on the track (must be a rack)
+    """
+    try:
+        ableton = get_ableton_connection()
+        result = ableton.send_command("get_rack_device_info", {"track_index": track_index, "device_index": device_index})
+        return json.dumps(result, indent=2)
+    except Exception as e:
+        logger.error(f"Error getting rack device info from Ableton: {str(e)}")
+        return f"Error getting rack device info: {str(e)}"
Evidence
The MCP server’s receive loop calls json.loads on the entire concatenated buffer after every recv to
check completeness (repeated full-buffer parses). The new endpoint returns a fully nested rack
structure and then json.dumps(..., indent=2), which increases payload size and makes that loop more
expensive and more likely to exceed the fixed socket timeout.

MCP_Server/server.py[46-90]
MCP_Server/server.py[268-302]
AbletonMCP_Remote_Script/init.py[428-445]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`get_rack_device_info` can produce large JSON responses. The server currently detects message completion by repeatedly attempting `json.loads` on the full accumulated buffer after each recv, which becomes expensive for large payloads.

### Issue Context
This is a pre-existing receive strategy, but the new endpoint makes large payloads much more likely.

### Fix Focus Areas
- MCP_Server/server.py[46-90]
- MCP_Server/server.py[268-302]

### Suggested changes
- Prefer a framing protocol so you can parse once:
 - Remote Script sends: `&lt;length&gt;\n&lt;json-bytes&gt;` (or similar)
 - Server reads length line then reads exact payload bytes
- If protocol changes are too heavy for now:
 - For `get_rack_device_info`, return `json.dumps(result)` without `indent=2` to reduce payload size.
 - Consider a larger timeout specifically for this endpoint (or a parameterized timeout).
 - Combine with serialization limits (max depth / max devices) so responses remain bounded.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment on lines +450 to +457
if track_index < 0 or track_index >= len(self._song.tracks):
raise IndexError("Track index out of range")

track = self._song.tracks[track_index]

if device_index < 0 or device_index >= len(track.devices):
raise IndexError("Device index out of range")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. indexerror breaks client loop 📘 Rule violation ⛯ Reliability

The new rack introspection command raises IndexError for invalid indices, and the client handler
treats non-ValueError exceptions as serious and breaks the connection. This makes simple bad input
an availability/reliability issue instead of a handled edge case.
Agent Prompt
## Issue description
Out-of-range indices currently raise `IndexError`, which leads the client handler to break the loop and disconnect.

## Issue Context
The client handler only treats `ValueError` as non-fatal; other exceptions trigger a disconnect.

## Fix Focus Areas
- AbletonMCP_Remote_Script/__init__.py[450-457]
- AbletonMCP_Remote_Script/__init__.py[198-200]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +460 to +462
if not device.can_have_chains:
raise ValueError("Device '{}' is not a rack and does not have chains".format(device.name))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

2. Exception exposes device.name 📘 Rule violation ⛨ Security

The new rack endpoint includes device.name in an exception message, and error handling sends
str(e) back to the client. This can leak internal session/device details to the caller.
Agent Prompt
## Issue description
The error message includes `device.name` and is propagated to clients via `str(e)`.

## Issue Context
User-facing error responses should be generic and not reveal internal session/device details.

## Fix Focus Areas
- AbletonMCP_Remote_Script/__init__.py[460-462]
- AbletonMCP_Remote_Script/__init__.py[184-187]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +428 to +445
def _serialize_device(self, device):
"""Serialize a device, recursively including chains for rack devices"""
device_info = {
"name": device.name,
"class_name": device.class_name,
"type": self._get_device_type(device)
}
if device.can_have_chains:
chains = []
for chain_index, chain in enumerate(device.chains):
chain_devices = [self._serialize_device(dev) for dev in chain.devices]
chains.append({
"index": chain_index,
"name": chain.name,
"devices": chain_devices
})
device_info["chains"] = chains
return device_info
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

3. Unbounded rack serialization 🐞 Bug ⛯ Reliability

New rack serialization recursively walks all nested racks/chains with no depth/size limits, so
deep/large racks can cause very slow responses, huge payloads, or a Python RecursionError. Large
payloads also increase the chance the Remote Script’s blocking sendall (no timeout) will stall a
client handler thread if the client is slow/disconnected.
Agent Prompt
### Issue description
`get_rack_device_info` recursively serializes nested racks without any depth/size limits. Deep or large racks can produce huge responses, hit Python recursion limits, and/or cause long blocking socket sends.

### Issue Context
This endpoint is designed to “drill in” and may be called on complex Ableton projects where nested racks/chains can be large.

### Fix Focus Areas
- AbletonMCP_Remote_Script/__init__.py[428-469]
- AbletonMCP_Remote_Script/__init__.py[133-177]

### Suggested changes
- Update `_serialize_device(device, depth=0, max_depth=..., budget=...)`:
  - Stop recursing past `max_depth` and/or when a `max_total_devices` budget is exceeded.
  - Include a field like `"truncated": true` or `"truncation_reason": "max_depth"` when limits are reached.
  - Optionally include `index` values for devices within each chain to make truncated results still navigable.
- Update `_get_rack_device_info` to accept optional params (e.g., `max_depth`, `max_total_devices`) from `params` and pass them through.
- Consider making the client handler safer for large responses:
  - Set a reasonable socket timeout for sends, or
  - Send in chunks and abort cleanly if the client disconnects / blocks too long.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

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