Skip to main content
Glama

play

Plays multi-track MIDI music compositions with customizable instruments, tempo, and note arrangements for testing or listening to created scores.

Instructions

Plays a music score

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
bpmYesThe BPM of the song
midiOuputNameNoThe MIDI output name to use. Don't add unless requested.
tracksYesArray of tracks to play. - If you want to make it a drum track, set the instrumentName to 'drums'. and Use the 'drums' proprerty in notation. - Otherwise, use the 'note' property in 'notes'. - Unless asked otherwise, add 10 bars assuming 4/4 time signature. - Unless asked otherwise, make sure that each has the same number of bars. - Sometimes you make some tracks longer or shorter than others. Avoid that.

Implementation Reference

  • The main handler function for the MCP 'play' tool. It creates a Midi instance, initializes it, and calls playScore with the provided input parameters (bpm, midiOutputName, tracks). Returns a text response indicating playback.
    handler: async (
      input: PlayMusicMcpToolInput
    ): Promise<{ content: { type: "text"; text: string }[] }> => {
      const midi = new Midi();
    
      await midi.init();
    
      await midi.playScore({
        bpm: input.bpm,
        midiOuputName: input.midiOuputName,
        tracks: input.tracks as any,
      });
    
      return {
        content: [
          {
            type: "text",
            text: "Playing music score",
          },
        ],
      };
    },
  • Zod input schema for the 'play' tool defining bpm, optional midiOutputName, and tracks array with instrument, channel, and notes/drums with durations.
    const inputSchema = {
      bpm: z.number().describe("The BPM of the song"),
      midiOuputName: z
        .string()
        .optional()
        .describe("The MIDI output name to use. Don't add unless requested."),
      tracks: z
        .array(
          z.object({
            instrumentName: z
              .enum([
                "drums",
                ...(Object.keys(Instruments) as [string, ...string[]]),
              ])
              .describe(
                `The instrument of the track. Available instruments: ${Object.keys(
                  Instruments
                ).join(
                  ", "
                )}. If you want to make it a drum track, set the instrumentName to 'drums'.`
              ),
            channel: z
              .number()
              .optional()
              .describe(
                "The MIDI channel of the track. Don't add unless requested."
              ),
            notes: z
              .array(
                z.object({
                  note: z
                    .array(z.string())
                    .nullable()
                    .optional()
                    .describe(
                      "The notes to play. Use array for chords. Or put one element for single note. Use an empty array for rest/silence"
                    ),
                  drums: z
                    .array(z.string())
                    .nullable()
                    .optional()
                    .describe(
                      "The drums to play. Use array for multiple drums. Use an empty array for rest/silence. Available drums: " +
                        Object.keys(Drums).join(", ")
                    ),
                  noteDuration: z
                    .string()
                    .describe(
                      "The note duration, e.g.: 1/32, 1/16, 1/8, 1/4, 1/2, 1"
                    ),
                })
              )
              .describe(
                `"Array of notes or drums to play with timing. 
                
                - If you want to play a drum track, use the drums property. 
                - If you want to play a non-drum instrument, use the note property.
                
                Example:
                
                [{note: ['C2', 'E2'], noteDuration: '1/8'}, {note: [], noteDuration: '1/8'}, {note: ['G2'], noteDuration: '1/8'}, {note: null, noteDuration: '1/8'}]. 
                
                Or 
                
                [{drums: ['bass_drum_1', 'closed_hi_hat'], noteDuration: '1/8'}, {drums: ['closed_hi_hat'], noteDuration: '1/8'}, {drums: ['closed_hi_hat', 'acoustic_snare'], noteDuration: '1/8'}, {drums: ['closed_hi_hat'], noteDuration: '1/8'}]. 
                
                An array could be a bar or several bars.
                --------------------------------------------------------------------------------
                  
                IMPORTANT FOR FOR DRUM TRACKS:
               
                - notes are played one after another. 
                - we wait until the whole duration of a note before we play another one. 
                - So don't do this: "notes" :[{"drums: ["bass_drum_1", "closed_hi_hat"], noteDuration: '1/4'},{"drums: [ "closed_hi_hat"], noteDuration: '1/4'} {drums: ['closed_hi_hat', 'acoustic_snare'], noteDuration: '1/4'}...].`
              ),
          })
        )
        .describe(
          `Array of tracks to play.
          
          - If you want to make it a drum track, set the instrumentName to 'drums'. and Use the 'drums' proprerty in notation. 
          - Otherwise, use the 'note' property in 'notes'.
          - Unless asked otherwise, add 10 bars assuming 4/4 time signature.
          - Unless asked otherwise, make sure that each has the same number of bars.
          - Sometimes you make some tracks longer or shorter than others. Avoid that.
          `
        ),
    };
    
    const inputSchemaObject = z.object(inputSchema);
  • Registration of the 'play' tool (PlayMusicMcpTool) on the MCP server using server.registerTool with name, metadata, and handler.
    server.registerTool(
      PlayMusicMcpTool.name,
      {
        title: PlayMusicMcpTool.title,
        description: PlayMusicMcpTool.description,
        inputSchema: PlayMusicMcpTool.inputSchema,
      },
      PlayMusicMcpTool.handler
    );
  • Definition of the PlayMusicMcpTool object including name 'play', title, description, inputSchema, and handler for use in MCP registration.
    const PlayMusicMcpTool = {
      name: "play",
      title: "Play a music score",
      description: "Plays a music score",
      inputSchema,
      handler: async (
        input: PlayMusicMcpToolInput
      ): Promise<{ content: { type: "text"; text: string }[] }> => {
        const midi = new Midi();
    
        await midi.init();
    
        await midi.playScore({
          bpm: input.bpm,
          midiOuputName: input.midiOuputName,
          tracks: input.tracks as any,
        });
    
        return {
          content: [
            {
              type: "text",
              text: "Playing music score",
            },
          ],
        };
      },
    };
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/mikeborozdin/vibe-composer-midi-mcp'

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