Skip to main content
Glama

create-items-in-bulk-using-file

Create multiple items on a Miro board in one operation using a JSON file from your device.

Instructions

Create multiple items on a Miro board in a single operation using a JSON file from device

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
boardIdYesUnique identifier (ID) of the board where the items will be created
fileDataYesBase64 encoded JSON file data containing items to create

Implementation Reference

  • Main handler function that decodes base64-encoded JSON file data containing items array, validates each item, creates sticky notes, cards, or text items on the Miro board using helper functions, collects results and errors, and returns a JSON summary.
    fn: async ({ boardId, fileData }) => {
      try {
        if (!boardId) {
          return ServerResponse.error("Board ID is required");
        }
        
        if (!fileData) {
          return ServerResponse.error("File data is required");
        }
    
        // Decode the base64 file data
        let jsonData;
        try {
          const base64Data = fileData.replace(/^data:application\/json;base64,/, '');
          const fileBuffer = Buffer.from(base64Data, 'base64');
          const fileContent = fileBuffer.toString('utf-8');
          jsonData = JSON.parse(fileContent);
        } catch (error) {
          return ServerResponse.error(`Error decoding or parsing JSON file data: ${error.message}`);
        }
    
        // Validate that the decoded data contains an 'items' array
        if (!jsonData.items || !Array.isArray(jsonData.items) || jsonData.items.length === 0) {
          return ServerResponse.error("JSON file must contain a non-empty 'items' array");
        }
    
        const items = jsonData.items;
        const results = [];
        const errors = [];
    
        const createPromises = items.map(async (item, index) => {
          try {
            // Validate item structure
            if (!item.type || !item.data || !item.position) {
              throw new Error(`Item at index ${index} is missing required fields (type, data, or position)`);
            }
    
            let result;
            
            if (item.type === 'sticky_note') {
              result = await createStickyNote(boardId, item);
            } else if (item.type === 'card') {
              result = await createCard(boardId, item);
            } else if (item.type === 'text') {
              result = await createText(boardId, item);
            } else {
              throw new Error(`Unsupported item type: ${item.type}`);
            }
            
            return { index, result };
          } catch (error) {
            return { index, error: error.message || String(error) };
          }
        });
        
        const promiseResults = await Promise.all(createPromises);
        
        for (const promiseResult of promiseResults) {
          const { index, result, error } = promiseResult;
          if (error) {
            errors.push({ index, error });
          } else if (result) {
            results.push({ index, item: result });
          }
        }
        
        return ServerResponse.text(JSON.stringify({
          created: results.length,
          failed: errors.length,
          results,
          errors
        }, null, 2));
        
      } catch (error) {
        return ServerResponse.error(error);
      }
    }
  • Tool schema definition including name, description, and Zod input schema for boardId and fileData parameters.
    const createItemsInBulkUsingFileTool: ToolSchema = {
      name: "create-items-in-bulk-using-file",
      description: "Create multiple items on a Miro board in a single operation using a JSON file from device",
      args: {
        boardId: z.string().describe("Unique identifier (ID) of the board where the items will be created"),
        fileData: z.string().describe("Base64 encoded JSON file data containing items to create")
      },
  • src/index.ts:185-185 (registration)
    Registration of the createItemsInBulkUsingFileTool in the ToolBootstrapper chain.
    .register(createItemsInBulkUsingFileTool)
  • Helper function to create a sticky note item on the board, validating and setting content, shape, position, and style properties before calling Miro API.
    async function createStickyNote(boardId: string, item: any) {
      const createRequest = new StickyNoteCreateRequest();
      
      const stickyNoteData = new StickyNoteData();
      stickyNoteData.content = item.data.content;
      stickyNoteData.shape = item.data.shape || 'square';
      
      createRequest.data = stickyNoteData;
      createRequest.position = item.position;
      
      if (item.style) {
        const style: Record<string, string> = {};
        
        if (item.style.fillColor) {
          if (validStickyNoteColors.includes(item.style.fillColor)) {
            style.fillColor = item.style.fillColor;
          } else {
            style.fillColor = 'light_yellow';
          }
        }
        
        if (item.style.textAlign) {
          if (validTextAligns.includes(item.style.textAlign)) {
            style.textAlign = item.style.textAlign;
          } else {
            style.textAlign = 'center';
          }
        }
        
        createRequest.style = style;
      }
      
      return await MiroClient.getApi().createStickyNoteItem(boardId, createRequest);
    }
  • Helper function to create a card item on the board, setting title, description, assignee, due date, position, and style.
    async function createCard(boardId: string, item: any) {
      const createRequest = new CardCreateRequest();
      
      const cardData = new CardData();
      cardData.title = item.data.title;
      
      if (item.data.description) {
        cardData.description = item.data.description;
      }
      
      if (item.data.assigneeId) {
        cardData.assigneeId = item.data.assigneeId;
      }
      
      if (item.data.dueDate) {
        cardData.dueDate = new Date(item.data.dueDate);
      }
      
      createRequest.data = cardData;
      createRequest.position = item.position;
      
      if (item.style) {
        createRequest.style = item.style as Record<string, any>;
      }
      
      return await MiroClient.getApi().createCardItem(boardId, createRequest);
    }
Behavior2/5

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

With no annotations provided, the description carries full burden but lacks critical behavioral details. It states it's a creation operation but doesn't disclose permissions required, rate limits, error handling, or what happens if the file data is malformed. For a bulk mutation tool, this is a significant gap in transparency.

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

Conciseness5/5

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

The description is a single, efficient sentence that front-loads key information: action, resource, and method. There's no wasted wording, making it appropriately concise and well-structured for quick understanding.

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?

For a bulk creation tool with no annotations and no output schema, the description is incomplete. It doesn't explain the JSON file structure, success/failure responses, or how errors are handled. Given the complexity of batch operations, more context is needed to guide effective use.

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

Parameters3/5

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

Schema description coverage is 100%, so the schema already documents both parameters thoroughly. The description adds minimal value by implying the JSON file contains 'items to create' but doesn't provide format examples or constraints beyond what the schema states. Baseline 3 is appropriate when schema does the heavy lifting.

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 ('create multiple items'), resource ('on a Miro board'), and method ('using a JSON file from device'), making the purpose specific and understandable. However, it doesn't explicitly differentiate from its sibling 'create-items-in-bulk' (which likely uses different input methods), missing full sibling distinction for a perfect score.

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?

The description provides no guidance on when to use this tool versus alternatives like 'create-items-in-bulk' or individual item creation tools. It mentions the method ('using a JSON file') but doesn't specify scenarios, prerequisites, or exclusions, leaving usage context unclear.

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/k-jarzyna/mcp-miro'

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