Skip to main content
Glama

assign_to_bank

Assigns an event to a specified bank in FMOD Studio, allowing events to belong to multiple banks for modular audio organization.

Instructions

Add the event to the given bank (event can live in multiple banks).

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
event_pathYes
bank_pathYes

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • Core implementation: evaluates JavaScript in FMOD Studio that looks up an event and a bank by path, adds the event to the bank's relationships, then returns the event path and list of assigned bank paths.
    async def assign_to_bank(
        client: StudioClient,
        event_path: str,
        bank_path: str,
    ) -> dict[str, Any]:
        js = f"""
            var evt = studio.project.lookup({json.dumps(event_path)});
            if (!evt) throw new Error("Event not found: " + {json.dumps(event_path)});
            var bank = studio.project.lookup({json.dumps(bank_path)});
            if (!bank) throw new Error("Bank not found: " + {json.dumps(bank_path)});
            evt.relationships.banks.add(bank);
            var paths = [];
            var dests = evt.relationships.banks.destinations;
            if (dests) for (var i = 0; i < dests.length; i++) paths.push(dests[i].getPath());
            return {{ path: evt.getPath(), banks: paths }};
        """
        return await client.eval(js)
  • FastMCP tool registration: decorates the server function with @mcp.tool() and delegates to events.assign_to_bank.
    @mcp.tool()
    async def assign_to_bank(event_path: str, bank_path: str) -> dict[str, Any]:
        """Add the event to the given bank (event can live in multiple banks)."""
        return await events.assign_to_bank(_studio(), event_path, bank_path)
  • Imports StudioClient used as the parameter type for the handler function.
    from ..studio_client import StudioClient
    
    
    # Shared JS helper: walks/creates nested EventFolders under the master folder
    # so that "event:/a/b/c" resolves to the folder object for "event:/a/b/" and
    # the leaf "c" is the event name. Uses only /* */ comments because studio_client
    # flattens the JS to a single line before sending.
    _FOLDER_HELPER = r"""
    function __mcp_ensureEventFolder(pathPrefix) {
        if (pathPrefix.indexOf("event:/") !== 0) throw new Error("Event path must start with 'event:/'");
        var remainder = pathPrefix.substring("event:/".length);
        if (remainder.charAt(remainder.length - 1) === "/") remainder = remainder.substring(0, remainder.length - 1);
        var segments = remainder.length > 0 ? remainder.split("/") : [];
        var cur = studio.project.workspace.masterEventFolder;
        if (!cur) throw new Error("Could not locate masterEventFolder");
        var builtPath = "event:/";
        for (var i = 0; i < segments.length; i++) {
            var seg = segments[i];
            if (!seg) continue;
            builtPath += seg + "/";
            var next = studio.project.lookup(builtPath);
            if (!next) {
                next = studio.project.create("EventFolder");
                next.name = seg;
                next.folder = cur;
            }
            cur = next;
        }
        return cur;
    }
    """
    
    
    async def create_event(
        client: StudioClient,
        event_path: str,
        bank_path: str,
        bus_path: str | None = None,
    ) -> dict[str, Any]:
        """Create a new event, assign it to a bank, and optionally route to a bus.
    
        ``event_path`` is the full path including the event name, e.g.
        ``event:/bumpers/hit_soft``. Any missing ancestor folders are created.
        ``bank_path`` like ``bank:/pinball_sound_effects``. ``bus_path`` like
        ``bus:/SFX`` (optional).
        """
        if "/" not in event_path or not event_path.startswith("event:/"):
            raise ValueError("event_path must look like 'event:/folder/name'")
        parent_prefix, _, name = event_path.rpartition("/")
        # Ensure trailing slash on parent for the helper
        parent_with_slash = parent_prefix + "/"
        js = (
            _FOLDER_HELPER
            + f"""
            var parent = __mcp_ensureEventFolder({json.dumps(parent_with_slash)});
            var existing = studio.project.lookup({json.dumps(event_path)});
            if (existing) throw new Error("Event already exists: " + {json.dumps(event_path)});
            var evt = studio.project.create("Event");
            evt.name = {json.dumps(name)};
            evt.folder = parent;
            var bank = studio.project.lookup({json.dumps(bank_path)});
            if (!bank) throw new Error("Bank not found: " + {json.dumps(bank_path)});
            evt.relationships.banks.add(bank);
            var busPath = {json.dumps(bus_path) if bus_path else "null"};
            if (busPath) {{
                var bus = studio.project.lookup(busPath);
                if (!bus) throw new Error("Bus not found: " + busPath);
                try {{ evt.masterTrack.mixerGroup.output = bus; }} catch (e) {{ throw new Error("Could not route to bus: " + e.message); }}
            }}
            return {{ guid: evt.id, path: evt.getPath(), bank: bank.getPath(), bus: busPath }};
        """
        )
        return await client.eval(js)
    
    
    async def add_single_sound(
        client: StudioClient,
        event_path: str,
        audio_guid: str,
        loop: bool = False,
        streaming: bool = False,
        async_mode: bool = False,
        start: float = 0.0,
        length: float | None = None,
    ) -> dict[str, Any]:
        """Add a new group track with a Single-Sound instrument to ``event_path``.
    
        The instrument's length defaults to the audio file's length if
        ``length`` is omitted.
        """
        length_js = "asset.length" if length is None else json.dumps(length)
        js = f"""
            var evt = studio.project.lookup({json.dumps(event_path)});
            if (!evt) throw new Error("Event not found: " + {json.dumps(event_path)});
            var asset = null;
            var all = studio.project.model.AudioFile.findInstances();
            for (var i = 0; i < all.length; i++) {{
                if (all[i].isValid && all[i].id === {json.dumps(audio_guid)}) {{ asset = all[i]; break; }}
            }}
            if (!asset) throw new Error("AudioFile not found for guid: " + {json.dumps(audio_guid)});
            var track = evt.addGroupTrack();
            var sound = track.addSound(evt.timeline, "SingleSound", {json.dumps(start)}, {length_js});
            sound.audioFile = asset;
            if (typeof sound.length !== 'undefined' && asset.length) sound.length = asset.length;
            try {{ sound.loopMode = {"'Loop'" if loop else "'Off'"}; }} catch (e) {{}}
            try {{ sound.streaming = {str(streaming).lower()}; }} catch (e) {{}}
            try {{ sound.asynchronous = {str(async_mode).lower()}; }} catch (e) {{}}
            return {{
                track_guid: track.id,
                instrument_guid: sound.id,
                audio_file_guid: asset.id,
                length: sound.length || null
            }};
        """
        return await client.eval(js)
    
    
    async def set_event_property(
        client: StudioClient,
        event_path: str,
        property_name: str,
        value: Any,
    ) -> dict[str, Any]:
        """Set a property on an event (volume, pitch, min/max distance, etc.)."""
        js = f"""
            var evt = studio.project.lookup({json.dumps(event_path)});
            if (!evt) throw new Error("Event not found: " + {json.dumps(event_path)});
            evt[{json.dumps(property_name)}] = {json.dumps(value)};
            return {{ ok: true, path: evt.getPath(), property: {json.dumps(property_name)}, value: evt[{json.dumps(property_name)}] }};
        """
        return await client.eval(js)
    
    
    async def assign_to_bank(
        client: StudioClient,
        event_path: str,
  • Test registration file confirms assign_to_bank is in the EXPECTED_TOOLS set.
    "assign_to_bank",
  • Test case verifying the handler sends the correct JavaScript ('evt.relationships.banks.add') to FMOD Studio.
    async def test_assign_to_bank(
        client: StudioClient, mock_studio: MockStudio
    ):
        mock_studio.responder = responder_sequence([("OK", {"path": "event:/a", "banks": ["bank:/X"]})])
        await events.assign_to_bank(client, "event:/a", "bank:/X")
        js = _last_sent_js(mock_studio)
Behavior2/5

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

Without annotations, the description must disclose behavioral traits. It only states the basic operation but does not reveal whether adding to a bank is idempotent, replaces existing assignments, or requires specific permissions. The note about events living in multiple banks implies non-destructiveness, but still lacks depth.

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?

The description is concise at one sentence, but it is overly minimal. It lacks structure such as bullet points or additional context. While concise, it sacrifices clarity and completeness.

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

Completeness2/5

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

Given the tool's simplicity and the presence of an output schema, the description still fails to provide sufficient context. It does not explain how to construct the event_path and bank_path, leaving the agent with too much ambiguity.

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

Parameters1/5

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

Schema description coverage is 0%, so the description must compensate. It only mentions 'event' and 'bank' without explaining what event_path and bank_path refer to or their required format. This adds no meaningful semantics beyond the parameter names.

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

Purpose4/5

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

The description clearly states the action: 'Add the event to the given bank', and notes the key property that events can live in multiple banks. This distinguishes it from sibling tools like create_event or set_event_property. However, it doesn't define what a 'bank' is in this context.

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 is provided on when to use this tool versus alternatives like assign_to_bus or create_event. There is no mention of prerequisites, when not to use it, or any ordering dependencies.

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/jmperez127/fmod-mcp'

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