Skip to main content
Glama
bschoepke

ableton-live-mcp

by bschoepke

live_get

Retrieve specific properties and children of an Ableton Live object by its reference, enabling direct access to device or track details.

Instructions

Resolve object; read selected properties/children.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
refYes
propertiesNo
childrenNo
child_limitNo
detailNo
max_itemsNo
max_depthNo
max_string_lengthNo
timeoutNoSeconds to wait for Live's main thread.

Implementation Reference

  • The 'forward' function creates a closure (lambda) that calls bridge.request(method, args). For live_get, the method is 'get', so the handler is: lambda args: bridge.request('get', args). This is the actual execution logic — it sends a 'get' request to the Ableton bridge with the tool's arguments.
    def forward(method: str):
        return lambda args: bridge.request(method, args)
  • src/server.py:59-68 (registration)
    The 'live_get' tool is registered with the MCP server at line 59. It has name 'live_get', description 'Resolve object; read selected properties/children.', accepts parameters: ref (required object with path/id), properties (array of strings), children (array or dict), child_limit (integer), plus optional response controls (detail, max_items, max_depth, max_string_length). The handler is set to forward('get').
    server.add_tool(Tool("live_get", "Resolve object; read selected properties/children.", schema({
        "ref": ref,
        "properties": {"type": "array", "items": {"type": "string"}},
        "children": {"oneOf": [
            {"type": "array", "items": {"type": "string"}},
            {"type": "object", "additionalProperties": {"type": "integer"}},
        ]},
        "child_limit": {"type": "integer", "minimum": 0},
        **response_controls,
    }, ["ref"]), forward("get")))
  • The 'ref' schema used by live_get defines the reference to a Live object, requiring either a 'path' (string) or an 'id' (integer).
    ref = {
        "type": "object",
        "properties": {
            "path": {"type": "string"},
            "id": {"type": "integer"},
        },
        "additionalProperties": False,
    }
  • The 'response_controls' dict defines shared optional parameters (detail, max_items, max_depth, max_string_length) that are spread into live_get's schema via **response_controls.
    response_controls = {
        "detail": {"type": "boolean"},
        "max_items": {"type": "integer"},
        "max_depth": {"type": "integer"},
        "max_string_length": {"type": "integer"},
        "timeout": {"type": "number", "description": "Seconds to wait for Live's main thread."},
    }
    mutation_controls = {
  • The 'request' method on AbletonBridgeClient is the underlying helper that the live_get handler calls. It sends a JSON-RPC request with the method name (e.g., 'get') and params to the Ableton Live bridge over a TCP socket, and returns the result.
    def request(self, method: str, params: dict[str, Any] | None = None) -> Any:
        params = params or {}
        payload = {
            "jsonrpc": "2.0",
            "id": next(self._ids),
            "method": method,
            "params": params,
        }
        with self._lock:
            try:
                response = self._send(payload)
            except OSError:
                self.close()
                try:
                    response = self._send(payload)
                except OSError as exc:
                    self.close()
                    raise AbletonBridgeError(f"Could not connect to Ableton bridge at {self.config.host}:{self.config.port}: {exc}") from exc
        message = json.loads(response.decode("utf-8"))
        if "error" in message:
            err = message["error"]
            detail = err.get("data") if os.environ.get("ABLETON_MCP_TRACEBACK") else ""
            suffix = f": {detail}" if detail else ""
            raise AbletonBridgeError(f"{err.get('code', -32000)} {err.get('message', 'Bridge error')}{suffix}")
        return message.get("result")
    
    def close(self) -> None:
        if self._sock is not None:
            try:
                self._sock.close()
            except OSError:
                pass
            self._sock = None
    
    def _send(self, payload: dict[str, Any]) -> bytes:
        sock = self._socket()
        request_timeout = self.config.timeout
        params = payload.get("params") or {}
        if isinstance(params, dict) and params.get("timeout") is not None:
            request_timeout = max(request_timeout, float(params["timeout"]) + 1.0)
        sock.settimeout(request_timeout)
        line = (json.dumps(payload, separators=(",", ":")) + "\n").encode("utf-8")
        sock.sendall(line)
        return self._read_line(sock, self.config.max_response_bytes)
    
    def _socket(self) -> socket.socket:
        if self._sock is None:
            self._sock = socket.create_connection((self.config.host, self.config.port), self.config.timeout)
            self._sock.settimeout(self.config.timeout)
        return self._sock
    
    @staticmethod
    def _read_line(sock: socket.socket, max_bytes: int = 8 * 1024 * 1024) -> bytes:
        chunks: list[bytes] = []
        total = 0
        while True:
            chunk = sock.recv(4096)
            if not chunk:
                break
            total += len(chunk)
            if max_bytes >= 0 and total > max_bytes:
Behavior1/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries full burden. It only says 'read' but does not disclose whether the operation is read-only, idempotent, or has side effects. No information about error handling, rate limits, or system impact.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single short sentence is concise, but for a tool with 9 parameters, it is likely too terse and lacks structure. Could be expanded without losing conciseness.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness1/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity (9 parameters, nested objects, no output schema), the description is severely inadequate. No return value info, no error conditions, no examples, and no guidance on how parameters interact.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is only 11% (only 'timeout' described). The description adds no meaning beyond parameter names; 'read selected properties/children' hints at two parameters but leaves the other seven (e.g., child_limit, detail, max_items) unexplained.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose3/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description states 'read selected properties/children,' which gives a clear verb and resource. However, the phrase 'Resolve object' is vague and could be more specific. It distinguishes from siblings like live_call or live_eval but not clearly from live_children.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance on when to use this tool versus alternatives such as live_children or live_observe. No mention of context, prerequisites, or exclusion criteria.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/bschoepke/ableton-live-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server