"""Live (macOS) — tool schemas and handlers. Extracted from server.py; see Engine/docs/03_SERVER_TOOLS.md for the tool catalog. """ from __future__ import annotations from pathlib import Path from typing import Sequence from mcp.types import TextContent, Tool from server_tools._shared import ( _text_result, _validate_filepath, _validate_output_path, generate_output_path, ) TOOLS = [ Tool( name="push_to_fcp", description="LIVE: send an FCPXML file into the running Final Cut Pro with zero clicks (official Open Document Apple event). Creates/targets a library via import-options. Launches FCP if needed. macOS-only; first use triggers an Automation permission prompt. For true zero-click, pass a library_location ending in .fcpbundle (a new path is auto-created); omitting it makes FCP show a modal library picker.", inputSchema={ "type": "object", "properties": { "filepath": {"type": "string", "description": "Path to FCPXML file or .fcpxmld bundle to import"}, "library_location": {"type": "string", "description": "Target .fcpbundle library path (auto-created if it doesn't exist; the extension is normalized to .fcpbundle). Omit to import into the active library, but note FCP then shows a modal 'Open Library' picker that blocks until answered"}, "suppress_warnings": {"type": "boolean", "description": "Suppress non-fatal import warning dialogs", "default": True}, "copy_assets": {"type": "boolean", "description": "Copy media into the library (true) or link in place (false). Omit for FCP default"}, }, "required": ["filepath"] } ), Tool( name="list_fcp_libraries", description="LIVE: enumerate the running Final Cut Pro's open libraries, events, and projects via Apple's read-only scripting dictionary. Refuses to launch FCP unless allow_launch is true. macOS-only.", inputSchema={ "type": "object", "properties": { "allow_launch": {"type": "boolean", "description": "Launch FCP if it isn't running", "default": False}, }, } ), ] async def handle_push_to_fcp(arguments: dict) -> Sequence[TextContent]: from fcpxml.live import push_to_fcp filepath = _validate_filepath(arguments["filepath"], ('.fcpxml', '.fcpxmld')) # Flat files get an options-injected sibling copy (never touch the # original); the copy path goes through the same write sandbox as # every other derived output. import_copy = None if Path(filepath).suffix.lower() == '.fcpxml': anchor = str(Path(filepath).resolve().parent) import_copy = _validate_output_path( generate_output_path(filepath, "_import"), anchor_dir=anchor ) result = push_to_fcp( filepath, library_location=arguments.get("library_location"), suppress_warnings=arguments.get("suppress_warnings", True), copy_assets=arguments.get("copy_assets"), import_copy_path=import_copy, ) lines = [ f"Sent to Final Cut Pro: {result['sent']}", f"FCP {'was launched' if result['launched_fcp'] else 'was already running'} — " f"import happens in-app (libraries/events are created or merged per import-options).", ] if arguments.get("library_location"): lines.append(f"Target library: {arguments['library_location']}") lines.append( "Note: Apple offers no programmatic export — to round-trip edits " "back, use File > Export XML in FCP." ) return _text_result("\n".join(lines)) async def handle_list_fcp_libraries(arguments: dict) -> Sequence[TextContent]: from fcpxml.live import list_fcp_libraries try: libraries = list_fcp_libraries( allow_launch=arguments.get("allow_launch", False) ) except RuntimeError as exc: return _text_result(str(exc)) if not libraries: return _text_result("Final Cut Pro is running but reports no open libraries.") lines = [f"Open libraries in Final Cut Pro ({len(libraries)}):", ""] for lib in libraries: lines.append(f"📚 {lib['name']}") for event in lib["events"]: lines.append(f" └─ {event['name']}") for proj in event["projects"]: lines.append(f" • {proj}") return _text_result("\n".join(lines)) HANDLERS = { "push_to_fcp": handle_push_to_fcp, "list_fcp_libraries": handle_list_fcp_libraries, }