Skip to content

Creating Tools

Learn how to create embed tools that return interactive web content.

Overview

An embed tool is an MCP tool that returns a toqanEmbed JSON structure. When your agent calls this tool, the frontend automatically renders the content as an iframe in the conversation.

Tool Structure

Every embed tool follows this pattern:

javascript
server.registerTool(
  "tool_name",
  {
    description: "Tool description for the agent",
    inputSchema: {},
  },
  async () => {
    const embedData = {
      toqanEmbed: {
        type: "iframe",
        url: "https://example.com",
        height: 700,
      },
    };

    return {
      content: [{ type: "text", text: JSON.stringify(embedData) }],
      structuredContent: { type: "iframe" },
    };
  },
);

Step-by-Step: Create a New Tool

Step 1: Create Tool File

Create a new file in src/mcp/tools/ (e.g., my-tool.js):

javascript
/**
 * Registers your custom tool on the MCP server
 * @param {import("@modelcontextprotocol/sdk/server/mcp.js").McpServer} server - The MCP server instance
 */
export function registerMyTool(server) {
  server.registerTool(
    "get_my_website",
    {
      description:
        "Returns my website. Use this tool when the user wants to view my website or learn more about me.",
      inputSchema: {},
    },
    async () => {
      const embedData = {
        toqanEmbed: {
          type: "iframe",
          url: "https://example.com",
          height: 700,
        },
      };

      return {
        content: [{ type: "text", text: JSON.stringify(embedData) }],
        structuredContent: { type: "iframe" },
      };
    },
  );
}

Step 2: Register the Tool

Add your tool to src/mcp/tools/index.js:

javascript
import { registerMyTool } from "./my-tool.js";

export function registerAllTools(server) {
  // ... existing tools
  registerMyTool(server);
}

Step 3: Test Your Tool

  1. Restart your server: npm start
  2. Call the tool from your agent
  3. Verify the iframe renders in the conversation

Embed JSON Schema

The toqanEmbed object must follow this structure:

typescript
{
  toqanEmbed: {
    type: "iframe";        // Only "iframe" is currently supported
    url: string;           // URL to embed (required)
    // OR
    src?: string;          // Alternative field name (also supported)
    height?: number;       // Height in pixels (default: 400)
  }
}

Example: External Website

Embed an external website directly:

javascript
server.registerTool(
  "get_ifood_website",
  {
    description:
      "Returns the iFood website. Use this tool when the user wants to order food, browse restaurants, or access iFood services.",
    inputSchema: {},
  },
  async () => {
    const embedData = {
      toqanEmbed: {
        type: "iframe",
        url: "https://www.ifood.com.br",
        height: 700,
      },
    };

    return {
      content: [{ type: "text", text: JSON.stringify(embedData) }],
      structuredContent: { type: "iframe" },
    };
  },
);

Example: Self-Hosted Widget

Serve your own HTML widget and embed it:

  1. Create HTML widget (e.g., website.html)
  2. Serve it via route (already configured at GET /website.html)
  3. Reference it in your tool:
javascript
server.registerTool(
  "get_my_widget",
  {
    description: "Returns my custom widget",
    inputSchema: {},
  },
  async () => {
    const embedData = {
      toqanEmbed: {
        type: "iframe",
        url: "https://your-mcp-server.com/website.html",
        height: 700,
      },
    };

    return {
      content: [{ type: "text", text: JSON.stringify(embedData) }],
      structuredContent: { type: "iframe" },
    };
  },
);

Best Practices

  1. Use descriptive tool names - Prefix with get_ for clarity
  2. Write clear descriptions - Help the agent understand when to use the tool
  3. Return URLs, not HTML - For performance, return URLs instead of inline HTML
  4. Set appropriate heights - Default is 400px, adjust based on content needs
  5. Use HTTPS - Required for iframe embedding in most browsers

Common Patterns

Dynamic URLs

javascript
async (args) => {
  const url = `https://example.com/widget?id=${args.id}`;
  return {
    content: [{
      type: "text",
      text: JSON.stringify({
        toqanEmbed: { type: "iframe", url, height: 700 }
      })
    }],
    structuredContent: { type: "iframe" },
  };
}

Conditional Embeds

javascript
async (args) => {
  const url = args.type === "preview" 
    ? "https://preview.example.com"
    : "https://example.com";
    
  return {
    content: [{
      type: "text",
      text: JSON.stringify({
        toqanEmbed: { type: "iframe", url, height: 700 }
      })
    }],
    structuredContent: { type: "iframe" },
  };
}

Next Steps