{
  "tools": [
    {
      "id": "accessible-palette",
      "category": "accessibility-tools",
      "built": true,
      "requirements": "Foreground/background contrast matrix; link actual ratios to editable color pairs.",
      "implementation": {
        "fields": [],
        "note": "Enter background hex colors separated by spaces. Chooses black or white text by contrast; does not certify complete interface accessibility.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Background hex colors",
          "placeholder": "#3366cc #ffffff",
          "help": "Separate hex colors with spaces. The result suggests black or white text for each. Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/accessibility-tools/accessible-palette/",
      "agent_url": "https://happytails.ai/agents/en/accessibility-tools/accessible-palette/"
    },
    {
      "id": "alt-text-generator",
      "category": "accessibility-tools",
      "built": true,
      "requirements": "Suggest concise image descriptions using optional page context; let users edit or mark decorative images; avoid sensitive identity guesses; human review before publication.",
      "implementation": {
        "fields": [],
        "files": true,
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "extra": true,
        "maxFileBytes": 20971520,
        "accept": ".png,.jpg,.jpeg,.webp",
        "note": "Local BLIP image descriptions. Suggestions can be wrong and do not include surrounding page context. Review and edit before publishing.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/alt-text-generator/run",
      "api": {
        "id": "alt-text-generator",
        "name": "Alt text generator",
        "category": "accessibility-tools",
        "description": "Local BLIP image descriptions.",
        "notes": "Local BLIP image descriptions. Suggestions can be wrong and do not include surrounding page context. Review and edit before publishing.",
        "human_path": "/en/accessibility-tools/alt-text-generator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/alt-text-generator/run",
        "schema_url": "/api/v1/tools/alt-text-generator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/accessibility-tools/alt-text-generator/",
      "agent_url": "https://happytails.ai/agents/en/accessibility-tools/alt-text-generator/"
    },
    {
      "id": "color-blindness-simulator",
      "category": "accessibility-tools",
      "built": true,
      "requirements": "Named simulation model, preview modes and clear limits of simulation.",
      "implementation": {
        "fields": [
          {
            "key": "mode",
            "label": "Simulation",
            "value": "Protanopia",
            "type": "select",
            "values": [
              "Protanopia",
              "Deuteranopia",
              "Tritanopia"
            ]
          }
        ],
        "files": true,
        "input": false,
        "note": "Approximate color-matrix simulation for design review, not a clinical representation or diagnostic test.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/accessibility-tools/color-blindness-simulator/",
      "agent_url": "https://happytails.ai/agents/en/accessibility-tools/color-blindness-simulator/"
    },
    {
      "id": "html-accessibility-checker",
      "category": "accessibility-tools",
      "built": true,
      "requirements": "Paste HTML with automated rule results; explain manual keyboard/screen-reader testing still required.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": false,
          "single": false,
          "label": "HTML source",
          "placeholder": "<p>Hello <strong>world</strong>.</p>",
          "help": "Paste HTML markup, not a website URL. Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/accessibility-tools/html-accessibility-checker/",
      "agent_url": "https://happytails.ai/agents/en/accessibility-tools/html-accessibility-checker/"
    },
    {
      "id": "7z-to-zip",
      "category": "archive-tools",
      "built": true,
      "requirements": "Repackage with explicit compression and filename handling.",
      "implementation": {
        "fields": [
          {
            "key": "password",
            "label": "Archive password (if needed)",
            "value": "",
            "type": "password"
          }
        ],
        "files": true,
        "accept": ".7z",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Processed by the local, self-hosted engine. No third-party conversion service is used. Exports a ZIP of extracted regular files. Paths, symbolic links, entry count, and expanded size are checked.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/7z-to-zip/run",
      "api": {
        "id": "7z-to-zip",
        "name": "7z to ZIP",
        "category": "archive-tools",
        "description": "Convert 7Z files to ZIP with the available format settings.",
        "notes": "Processed by the local, self-hosted engine. No third-party conversion service is used. Exports a ZIP of extracted regular files. Paths, symbolic links, entry count, and expanded size are checked.",
        "human_path": "/en/archive-tools/7z-to-zip/",
        "method": "POST",
        "endpoint": "/api/v1/tools/7z-to-zip/run",
        "schema_url": "/api/v1/tools/7z-to-zip",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "password": {
                  "type": "string",
                  "description": "Archive password (if needed)",
                  "default": ""
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/archive-tools/7z-to-zip/",
      "agent_url": "https://happytails.ai/agents/en/archive-tools/7z-to-zip/"
    },
    {
      "id": "bulk-rename",
      "category": "archive-tools",
      "built": true,
      "requirements": "Preview naming rules and collisions; operate on user-selected copies.",
      "implementation": {
        "fields": [
          {
            "key": "prefix",
            "label": "Filename prefix",
            "value": "file-",
            "type": "text"
          }
        ],
        "files": true,
        "multiple": true,
        "input": false,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/bulk-rename/run",
      "api": {
        "id": "bulk-rename",
        "name": "Bulk rename",
        "category": "archive-tools",
        "description": "Preview naming rules and collisions.",
        "notes": "",
        "human_path": "/en/archive-tools/bulk-rename/",
        "method": "POST",
        "endpoint": "/api/v1/tools/bulk-rename/run",
        "schema_url": "/api/v1/tools/bulk-rename",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "prefix": {
                  "type": "string",
                  "description": "Filename prefix",
                  "default": "file-"
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 20,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 20,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/archive-tools/bulk-rename/",
      "agent_url": "https://happytails.ai/agents/en/archive-tools/bulk-rename/"
    },
    {
      "id": "create-tar",
      "category": "archive-tools",
      "built": true,
      "requirements": "Bundle paths safely; explain TAR packaging versus compression.",
      "implementation": {
        "fields": [],
        "files": true,
        "multiple": true,
        "input": false,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/create-tar/run",
      "api": {
        "id": "create-tar",
        "name": "Create tar",
        "category": "archive-tools",
        "description": "Bundle paths safely.",
        "notes": "",
        "human_path": "/en/archive-tools/create-tar/",
        "method": "POST",
        "endpoint": "/api/v1/tools/create-tar/run",
        "schema_url": "/api/v1/tools/create-tar",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 20,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 20,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/archive-tools/create-tar/",
      "agent_url": "https://happytails.ai/agents/en/archive-tools/create-tar/"
    },
    {
      "id": "create-zip",
      "category": "archive-tools",
      "built": true,
      "requirements": "Select multiple files with predictable folder/name handling and download size feedback.",
      "implementation": {
        "fields": [],
        "files": true,
        "multiple": true,
        "input": false,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/create-zip/run",
      "api": {
        "id": "create-zip",
        "name": "Create ZIP",
        "category": "archive-tools",
        "description": "Select multiple files with predictable folder/name handling and download size feedback.",
        "notes": "",
        "human_path": "/en/archive-tools/create-zip/",
        "method": "POST",
        "endpoint": "/api/v1/tools/create-zip/run",
        "schema_url": "/api/v1/tools/create-zip",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 20,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 20,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/archive-tools/create-zip/",
      "agent_url": "https://happytails.ai/agents/en/archive-tools/create-zip/"
    },
    {
      "id": "extract-7z",
      "category": "archive-tools",
      "built": true,
      "requirements": "Memory limits, encrypted archives and supported codecs tested.",
      "implementation": {
        "fields": [
          {
            "key": "password",
            "label": "Archive password (if needed)",
            "value": "",
            "type": "password"
          }
        ],
        "files": true,
        "accept": ".7z",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Processed by the local, self-hosted engine. No third-party conversion service is used. Exports a ZIP of extracted regular files. Paths, symbolic links, entry count, and expanded size are checked.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/extract-7z/run",
      "api": {
        "id": "extract-7z",
        "name": "Extract 7z",
        "category": "archive-tools",
        "description": "Unpack a 7z archive and download its contents as a ZIP.",
        "notes": "Processed by the local, self-hosted engine. No third-party conversion service is used. Exports a ZIP of extracted regular files. Paths, symbolic links, entry count, and expanded size are checked.",
        "human_path": "/en/archive-tools/extract-7z/",
        "method": "POST",
        "endpoint": "/api/v1/tools/extract-7z/run",
        "schema_url": "/api/v1/tools/extract-7z",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "password": {
                  "type": "string",
                  "description": "Archive password (if needed)",
                  "default": ""
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/archive-tools/extract-7z/",
      "agent_url": "https://happytails.ai/agents/en/archive-tools/extract-7z/"
    },
    {
      "id": "extract-rar",
      "category": "archive-tools",
      "built": true,
      "requirements": "Decode supported RAR variants with expanded-size controls and clear password handling.",
      "implementation": {
        "fields": [
          {
            "key": "password",
            "label": "Archive password (if needed)",
            "value": "",
            "type": "password"
          }
        ],
        "files": true,
        "accept": ".rar",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Processed by the local, self-hosted engine. No third-party conversion service is used. Exports a ZIP of extracted regular files. Paths, symbolic links, entry count, and expanded size are checked.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/extract-rar/run",
      "api": {
        "id": "extract-rar",
        "name": "Extract rar",
        "category": "archive-tools",
        "description": "Unpack supported RAR files and download their contents as a ZIP.",
        "notes": "Processed by the local, self-hosted engine. No third-party conversion service is used. Exports a ZIP of extracted regular files. Paths, symbolic links, entry count, and expanded size are checked.",
        "human_path": "/en/archive-tools/extract-rar/",
        "method": "POST",
        "endpoint": "/api/v1/tools/extract-rar/run",
        "schema_url": "/api/v1/tools/extract-rar",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "password": {
                  "type": "string",
                  "description": "Archive password (if needed)",
                  "default": ""
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/archive-tools/extract-rar/",
      "agent_url": "https://happytails.ai/agents/en/archive-tools/extract-rar/"
    },
    {
      "id": "extract-tar-gz",
      "category": "archive-tools",
      "built": true,
      "requirements": "Unwrap gzip and tar; sanitize paths and limit decompression.",
      "implementation": {
        "fields": [],
        "files": true,
        "input": false,
        "accept": ".tar,.gz,.tgz",
        "note": "Supports basic USTAR/TAR.GZ archives; rejects links and unsupported extended headers. Maximum 100 MB expanded data.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/extract-tar-gz/run",
      "api": {
        "id": "extract-tar-gz",
        "name": "Extract tar gz",
        "category": "archive-tools",
        "description": "Unwrap gzip and tar.",
        "notes": "Supports basic USTAR/TAR.GZ archives; rejects links and unsupported extended headers. Maximum 100 MB expanded data.",
        "human_path": "/en/archive-tools/extract-tar-gz/",
        "method": "POST",
        "endpoint": "/api/v1/tools/extract-tar-gz/run",
        "schema_url": "/api/v1/tools/extract-tar-gz",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/archive-tools/extract-tar-gz/",
      "agent_url": "https://happytails.ai/agents/en/archive-tools/extract-tar-gz/"
    },
    {
      "id": "extract-zip",
      "category": "archive-tools",
      "built": true,
      "requirements": "List before extracting, sanitize paths, limit expanded bytes and surface unsupported encryption.",
      "implementation": {
        "fields": [],
        "files": true,
        "input": false,
        "accept": ".zip",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/extract-zip/run",
      "api": {
        "id": "extract-zip",
        "name": "Extract ZIP",
        "category": "archive-tools",
        "description": "List before extracting, sanitize paths, limit expanded bytes and surface unsupported encryption.",
        "notes": "",
        "human_path": "/en/archive-tools/extract-zip/",
        "method": "POST",
        "endpoint": "/api/v1/tools/extract-zip/run",
        "schema_url": "/api/v1/tools/extract-zip",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/archive-tools/extract-zip/",
      "agent_url": "https://happytails.ai/agents/en/archive-tools/extract-zip/"
    },
    {
      "id": "join-files",
      "category": "archive-tools",
      "built": true,
      "requirements": "Require correct ordered binary parts; no claim to merge arbitrary documents.",
      "implementation": {
        "fields": [
          {
            "key": "name",
            "label": "Output filename",
            "value": "joined-file.bin",
            "type": "text"
          }
        ],
        "files": true,
        "multiple": true,
        "input": false,
        "note": "Joins raw parts in filename order, not separate PDF/video documents.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/join-files/run",
      "api": {
        "id": "join-files",
        "name": "Join files",
        "category": "archive-tools",
        "description": "Require correct ordered binary parts.",
        "notes": "Joins raw parts in filename order, not separate PDF/video documents.",
        "human_path": "/en/archive-tools/join-files/",
        "method": "POST",
        "endpoint": "/api/v1/tools/join-files/run",
        "schema_url": "/api/v1/tools/join-files",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "name": {
                  "type": "string",
                  "description": "Output filename",
                  "default": "joined-file.bin"
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 20,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 20,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/archive-tools/join-files/",
      "agent_url": "https://happytails.ai/agents/en/archive-tools/join-files/"
    },
    {
      "id": "list-archive-contents",
      "category": "archive-tools",
      "built": true,
      "requirements": "List filenames/sizes without expanding all files; distinguish ZIP coverage from all archives.",
      "implementation": {
        "fields": [],
        "files": true,
        "input": false,
        "accept": ".zip",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/list-archive-contents/run",
      "api": {
        "id": "list-archive-contents",
        "name": "List archive contents",
        "category": "archive-tools",
        "description": "List filenames/sizes without expanding all files.",
        "notes": "",
        "human_path": "/en/archive-tools/list-archive-contents/",
        "method": "POST",
        "endpoint": "/api/v1/tools/list-archive-contents/run",
        "schema_url": "/api/v1/tools/list-archive-contents",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/archive-tools/list-archive-contents/",
      "agent_url": "https://happytails.ai/agents/en/archive-tools/list-archive-contents/"
    },
    {
      "id": "password-protect-zip",
      "category": "archive-tools",
      "built": true,
      "requirements": "Specify supported encryption and reader compatibility; no secret retention.",
      "implementation": {
        "fields": [
          {
            "key": "password",
            "label": "Archive password",
            "value": "",
            "type": "password"
          }
        ],
        "files": true,
        "multiple": true,
        "input": false,
        "note": "AES-256 encrypted ZIP. Filenames remain visible; some built-in extractors do not support AES ZIP.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/password-protect-zip/run",
      "api": {
        "id": "password-protect-zip",
        "name": "Password protect ZIP",
        "category": "archive-tools",
        "description": "Specify supported encryption and reader compatibility.",
        "notes": "AES-256 encrypted ZIP. Filenames remain visible; some built-in extractors do not support AES ZIP.",
        "human_path": "/en/archive-tools/password-protect-zip/",
        "method": "POST",
        "endpoint": "/api/v1/tools/password-protect-zip/run",
        "schema_url": "/api/v1/tools/password-protect-zip",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "password": {
                  "type": "string",
                  "description": "Archive password",
                  "default": ""
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 20,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 20,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/archive-tools/password-protect-zip/",
      "agent_url": "https://happytails.ai/agents/en/archive-tools/password-protect-zip/"
    },
    {
      "id": "rar-to-zip",
      "category": "archive-tools",
      "built": true,
      "requirements": "Extract/repackage rather than renaming extension; preserve filenames.",
      "implementation": {
        "fields": [
          {
            "key": "password",
            "label": "Archive password (if needed)",
            "value": "",
            "type": "password"
          }
        ],
        "files": true,
        "accept": ".rar",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Processed by the local, self-hosted engine. No third-party conversion service is used. Exports a ZIP of extracted regular files. Paths, symbolic links, entry count, and expanded size are checked.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/rar-to-zip/run",
      "api": {
        "id": "rar-to-zip",
        "name": "Rar to ZIP",
        "category": "archive-tools",
        "description": "Convert RAR files to ZIP with the available format settings.",
        "notes": "Processed by the local, self-hosted engine. No third-party conversion service is used. Exports a ZIP of extracted regular files. Paths, symbolic links, entry count, and expanded size are checked.",
        "human_path": "/en/archive-tools/rar-to-zip/",
        "method": "POST",
        "endpoint": "/api/v1/tools/rar-to-zip/run",
        "schema_url": "/api/v1/tools/rar-to-zip",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "password": {
                  "type": "string",
                  "description": "Archive password (if needed)",
                  "default": ""
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/archive-tools/rar-to-zip/",
      "agent_url": "https://happytails.ai/agents/en/archive-tools/rar-to-zip/"
    },
    {
      "id": "split-file",
      "category": "archive-tools",
      "built": true,
      "requirements": "Chunk sizes, filenames and reconstruction instructions; byte-exact roundtrip.",
      "implementation": {
        "fields": [
          {
            "key": "mb",
            "label": "Part size (MB)",
            "value": 10,
            "type": "number"
          }
        ],
        "files": true,
        "input": false,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/split-file/run",
      "api": {
        "id": "split-file",
        "name": "Split file",
        "category": "archive-tools",
        "description": "Chunk sizes, filenames and reconstruction instructions.",
        "notes": "",
        "human_path": "/en/archive-tools/split-file/",
        "method": "POST",
        "endpoint": "/api/v1/tools/split-file/run",
        "schema_url": "/api/v1/tools/split-file",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "mb": {
                  "type": "number",
                  "description": "Part size (MB)",
                  "default": 10.0
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/archive-tools/split-file/",
      "agent_url": "https://happytails.ai/agents/en/archive-tools/split-file/"
    },
    {
      "id": "barcode-generator",
      "category": "business-tools",
      "built": true,
      "requirements": "Code128/EAN/UPC formats, check digits and print sizes; no allocation of product identifiers.",
      "implementation": {
        "fields": [
          {
            "key": "format",
            "label": "Barcode format",
            "value": "CODE128",
            "type": "select",
            "values": [
              "CODE128",
              "EAN13",
              "EAN8",
              "UPC",
              "CODE39",
              "ITF14"
            ]
          }
        ],
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/business-tools/barcode-generator/",
      "agent_url": "https://happytails.ai/agents/en/business-tools/barcode-generator/"
    },
    {
      "id": "barcode-reader",
      "category": "business-tools",
      "built": true,
      "requirements": "Local image/camera detection with supported symbology list; return payload literally.",
      "implementation": {
        "fields": [],
        "files": true,
        "input": false,
        "accept": "image/*",
        "note": "Decodes locally. A readable code is not proof that the embedded link is safe.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/business-tools/barcode-reader/",
      "agent_url": "https://happytails.ai/agents/en/business-tools/barcode-reader/"
    },
    {
      "id": "hourly-to-salary",
      "category": "business-tools",
      "built": true,
      "requirements": "Hours per week and paid weeks; arithmetic gross estimate with no tax inference.",
      "implementation": {
        "fields": [
          {
            "key": "rate",
            "label": "Hourly pay",
            "value": 25,
            "type": "number"
          },
          {
            "key": "hours",
            "label": "Hours per week",
            "value": 40,
            "type": "number"
          },
          {
            "key": "weeks",
            "label": "Paid weeks per year",
            "value": 52,
            "type": "number"
          }
        ],
        "input": false,
        "note": "Gross pay before deductions.",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/hourly-to-salary/run",
      "api": {
        "id": "hourly-to-salary",
        "name": "Hourly to salary",
        "category": "business-tools",
        "description": "Estimate annual and monthly gross pay from an hourly rate.",
        "notes": "Gross pay before deductions.",
        "human_path": "/en/business-tools/hourly-to-salary/",
        "method": "POST",
        "endpoint": "/api/v1/tools/hourly-to-salary/run",
        "schema_url": "/api/v1/tools/hourly-to-salary",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "rate": {
                  "type": "number",
                  "description": "Hourly pay",
                  "default": 25.0
                },
                "hours": {
                  "type": "number",
                  "description": "Hours per week",
                  "default": 40.0
                },
                "weeks": {
                  "type": "number",
                  "description": "Paid weeks per year",
                  "default": 52.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/business-tools/hourly-to-salary/",
      "agent_url": "https://happytails.ai/agents/en/business-tools/hourly-to-salary/"
    },
    {
      "id": "invoice-generator",
      "category": "business-tools",
      "built": true,
      "requirements": "Editable line items, discounts, currencies and tax inputs; preview PDF and local saving.",
      "implementation": {
        "fields": [
          {
            "key": "number",
            "label": "Document number",
            "value": "INV-001",
            "type": "text"
          },
          {
            "key": "from",
            "label": "Your business",
            "value": "",
            "type": "text"
          },
          {
            "key": "to",
            "label": "Customer",
            "value": "",
            "type": "text"
          },
          {
            "key": "date",
            "label": "Date",
            "value": "2026-09-28",
            "type": "date"
          },
          {
            "key": "currency",
            "label": "Currency",
            "value": "EUR",
            "type": "text"
          },
          {
            "key": "tax",
            "label": "Tax (%)",
            "value": 0,
            "type": "number"
          }
        ],
        "note": "Basic line-item PDF, with tax added after subtotal and amounts rounded to cents. Review local invoice requirements. Standard font supports basic Latin text.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Invoice line items (JSON)",
          "placeholder": "[{\"description\":\"Design work\",\"quantity\":2,\"price\":50}]",
          "help": "Enter a JSON array of items with description, quantity and price. Fill in the business and customer details below. Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/invoice-generator/run",
      "api": {
        "id": "invoice-generator",
        "name": "Invoice generator",
        "category": "business-tools",
        "description": "Editable line items, discounts, currencies and tax inputs.",
        "notes": "Basic line-item PDF, with tax added after subtotal and amounts rounded to cents. Review local invoice requirements. Standard font supports basic Latin text.",
        "human_path": "/en/business-tools/invoice-generator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/invoice-generator/run",
        "schema_url": "/api/v1/tools/invoice-generator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "number": {
                  "type": "string",
                  "description": "Document number",
                  "default": "INV-001"
                },
                "from": {
                  "type": "string",
                  "description": "Your business",
                  "default": ""
                },
                "to": {
                  "type": "string",
                  "description": "Customer",
                  "default": ""
                },
                "date": {
                  "type": "string",
                  "description": "Date",
                  "default": "2026-09-28"
                },
                "currency": {
                  "type": "string",
                  "description": "Currency",
                  "default": "EUR"
                },
                "tax": {
                  "type": "number",
                  "description": "Tax (%)",
                  "default": 0.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/business-tools/invoice-generator/",
      "agent_url": "https://happytails.ai/agents/en/business-tools/invoice-generator/"
    },
    {
      "id": "meeting-cost",
      "category": "business-tools",
      "built": true,
      "requirements": "Participant count, durations and user-entered hourly rates; explicit currency and assumptions.",
      "implementation": {
        "fields": [
          {
            "key": "people",
            "label": "Attendees",
            "value": 5,
            "type": "number"
          },
          {
            "key": "rate",
            "label": "Hourly cost per person",
            "value": 40,
            "type": "number"
          },
          {
            "key": "minutes",
            "label": "Minutes",
            "value": 30,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/meeting-cost/run",
      "api": {
        "id": "meeting-cost",
        "name": "Meeting cost",
        "category": "business-tools",
        "description": "Estimate a meeting’s total staff cost.",
        "notes": "",
        "human_path": "/en/business-tools/meeting-cost/",
        "method": "POST",
        "endpoint": "/api/v1/tools/meeting-cost/run",
        "schema_url": "/api/v1/tools/meeting-cost",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "people": {
                  "type": "number",
                  "description": "Attendees",
                  "default": 5.0
                },
                "rate": {
                  "type": "number",
                  "description": "Hourly cost per person",
                  "default": 40.0
                },
                "minutes": {
                  "type": "number",
                  "description": "Minutes",
                  "default": 30.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/business-tools/meeting-cost/",
      "agent_url": "https://happytails.ai/agents/en/business-tools/meeting-cost/"
    },
    {
      "id": "qr-code-reader",
      "category": "business-tools",
      "built": true,
      "requirements": "Local image/camera decode; display destination before any navigation.",
      "implementation": {
        "fields": [],
        "files": true,
        "input": false,
        "accept": "image/*",
        "note": "Decodes locally. A readable code is not proof that the embedded link is safe.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/business-tools/qr-code-reader/",
      "agent_url": "https://happytails.ai/agents/en/business-tools/qr-code-reader/"
    },
    {
      "id": "quote-generator",
      "category": "business-tools",
      "built": true,
      "requirements": "Business estimate template with validity and line items; separate from inspirational quotes intent.",
      "implementation": {
        "fields": [
          {
            "key": "number",
            "label": "Document number",
            "value": "INV-001",
            "type": "text"
          },
          {
            "key": "from",
            "label": "Your business",
            "value": "",
            "type": "text"
          },
          {
            "key": "to",
            "label": "Customer",
            "value": "",
            "type": "text"
          },
          {
            "key": "date",
            "label": "Date",
            "value": "2026-09-28",
            "type": "date"
          },
          {
            "key": "currency",
            "label": "Currency",
            "value": "EUR",
            "type": "text"
          },
          {
            "key": "tax",
            "label": "Tax (%)",
            "value": 0,
            "type": "number"
          }
        ],
        "note": "Basic line-item PDF, with tax added after subtotal and amounts rounded to cents. Review local invoice requirements. Standard font supports basic Latin text.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Quote line items (JSON)",
          "placeholder": "[{\"description\":\"Design work\",\"quantity\":2,\"price\":50}]",
          "help": "Enter a JSON array of items with description, quantity and price. Fill in the business and customer details below. Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/quote-generator/run",
      "api": {
        "id": "quote-generator",
        "name": "Quote generator",
        "category": "business-tools",
        "description": "Business estimate template with validity and line items.",
        "notes": "Basic line-item PDF, with tax added after subtotal and amounts rounded to cents. Review local invoice requirements. Standard font supports basic Latin text.",
        "human_path": "/en/business-tools/quote-generator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/quote-generator/run",
        "schema_url": "/api/v1/tools/quote-generator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "number": {
                  "type": "string",
                  "description": "Document number",
                  "default": "INV-001"
                },
                "from": {
                  "type": "string",
                  "description": "Your business",
                  "default": ""
                },
                "to": {
                  "type": "string",
                  "description": "Customer",
                  "default": ""
                },
                "date": {
                  "type": "string",
                  "description": "Date",
                  "default": "2026-09-28"
                },
                "currency": {
                  "type": "string",
                  "description": "Currency",
                  "default": "EUR"
                },
                "tax": {
                  "type": "number",
                  "description": "Tax (%)",
                  "default": 0.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/business-tools/quote-generator/",
      "agent_url": "https://happytails.ai/agents/en/business-tools/quote-generator/"
    },
    {
      "id": "average",
      "category": "calculators",
      "built": true,
      "requirements": "Mean, median and range with input validation and visible formulas.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Numbers",
          "placeholder": "2, 4, 6",
          "help": "Separate numbers with commas, spaces or new lines. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/average/run",
      "api": {
        "id": "average",
        "name": "Average",
        "category": "calculators",
        "description": "Find the mean, median, sum, minimum, and maximum of a list of numbers.",
        "notes": "",
        "human_path": "/en/calculators/average/",
        "method": "POST",
        "endpoint": "/api/v1/tools/average/run",
        "schema_url": "/api/v1/tools/average",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/calculators/average/",
      "agent_url": "https://happytails.ai/agents/en/calculators/average/"
    },
    {
      "id": "break-even",
      "category": "calculators",
      "built": true,
      "requirements": "Fixed cost, variable cost and unit price; show infeasible/nonpositive contribution cases.",
      "implementation": {
        "fields": [
          {
            "key": "fixed",
            "label": "Fixed costs",
            "value": 1000,
            "type": "number"
          },
          {
            "key": "price",
            "label": "Price per unit",
            "value": 25,
            "type": "number"
          },
          {
            "key": "cost",
            "label": "Variable cost per unit",
            "value": 10,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/break-even/run",
      "api": {
        "id": "break-even",
        "name": "Break even",
        "category": "calculators",
        "description": "Find how many units cover your fixed and variable costs.",
        "notes": "",
        "human_path": "/en/calculators/break-even/",
        "method": "POST",
        "endpoint": "/api/v1/tools/break-even/run",
        "schema_url": "/api/v1/tools/break-even",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "fixed": {
                  "type": "number",
                  "description": "Fixed costs",
                  "default": 1000.0
                },
                "price": {
                  "type": "number",
                  "description": "Price per unit",
                  "default": 25.0
                },
                "cost": {
                  "type": "number",
                  "description": "Variable cost per unit",
                  "default": 10.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/calculators/break-even/",
      "agent_url": "https://happytails.ai/agents/en/calculators/break-even/"
    },
    {
      "id": "circle",
      "category": "calculators",
      "built": true,
      "requirements": "Radius/diameter/circumference/area modes with consistent units.",
      "implementation": {
        "fields": [
          {
            "key": "r",
            "label": "Radius",
            "value": 5,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/circle/run",
      "api": {
        "id": "circle",
        "name": "Circle",
        "category": "calculators",
        "description": "Calculate a circle’s diameter, circumference, and area from its radius.",
        "notes": "",
        "human_path": "/en/calculators/circle/",
        "method": "POST",
        "endpoint": "/api/v1/tools/circle/run",
        "schema_url": "/api/v1/tools/circle",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "r": {
                  "type": "number",
                  "description": "Radius",
                  "default": 5.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/calculators/circle/",
      "agent_url": "https://happytails.ai/agents/en/calculators/circle/"
    },
    {
      "id": "coin-flip",
      "category": "calculators",
      "built": true,
      "requirements": "Local random outcomes and optional repeated trials; no gambling predictions.",
      "implementation": {
        "fields": [],
        "input": false,
        "note": "",
        "live": false,
        "presentation": "metrics",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/coin-flip/run",
      "api": {
        "id": "coin-flip",
        "name": "Coin flip",
        "category": "calculators",
        "description": "Flip a virtual coin and get Heads or Tails.",
        "notes": "",
        "human_path": "/en/calculators/coin-flip/",
        "method": "POST",
        "endpoint": "/api/v1/tools/coin-flip/run",
        "schema_url": "/api/v1/tools/coin-flip",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/calculators/coin-flip/",
      "agent_url": "https://happytails.ai/agents/en/calculators/coin-flip/"
    },
    {
      "id": "dice-roller",
      "category": "calculators",
      "built": true,
      "requirements": "Dice count/sides and readable results; uniform random outcomes.",
      "implementation": {
        "fields": [
          {
            "key": "sides",
            "label": "Sides",
            "value": 6,
            "type": "number"
          },
          {
            "key": "n",
            "label": "Dice",
            "value": 2,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": false,
        "presentation": "metrics",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/dice-roller/run",
      "api": {
        "id": "dice-roller",
        "name": "Dice roller",
        "category": "calculators",
        "description": "Roll virtual dice and see each roll and the total.",
        "notes": "",
        "human_path": "/en/calculators/dice-roller/",
        "method": "POST",
        "endpoint": "/api/v1/tools/dice-roller/run",
        "schema_url": "/api/v1/tools/dice-roller",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "sides": {
                  "type": "number",
                  "description": "Sides",
                  "default": 6.0
                },
                "n": {
                  "type": "number",
                  "description": "Dice",
                  "default": 2.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/calculators/dice-roller/",
      "agent_url": "https://happytails.ai/agents/en/calculators/dice-roller/"
    },
    {
      "id": "discount",
      "category": "calculators",
      "built": true,
      "requirements": "Original/final price, percent saved, sequential discounts and explicit tax exclusion.",
      "implementation": {
        "fields": [
          {
            "key": "p",
            "label": "Price",
            "value": 100,
            "type": "number"
          },
          {
            "key": "d",
            "label": "Discount (%)",
            "value": 20,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/discount/run",
      "api": {
        "id": "discount",
        "name": "Discount",
        "category": "calculators",
        "description": "Calculate the saving and final price after a discount.",
        "notes": "",
        "human_path": "/en/calculators/discount/",
        "method": "POST",
        "endpoint": "/api/v1/tools/discount/run",
        "schema_url": "/api/v1/tools/discount",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "p": {
                  "type": "number",
                  "description": "Price",
                  "default": 100.0
                },
                "d": {
                  "type": "number",
                  "description": "Discount (%)",
                  "default": 20.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/calculators/discount/",
      "agent_url": "https://happytails.ai/agents/en/calculators/discount/"
    },
    {
      "id": "fractions",
      "category": "calculators",
      "built": true,
      "requirements": "Exact rational arithmetic and mixed-number simplification.",
      "implementation": {
        "fields": [
          {
            "key": "a",
            "label": "Numerator A",
            "value": 1,
            "type": "number"
          },
          {
            "key": "b",
            "label": "Denominator A",
            "value": 2,
            "type": "number"
          },
          {
            "key": "op",
            "label": "Operation",
            "value": "+",
            "type": "select",
            "values": [
              "+",
              "-",
              "×",
              "÷"
            ]
          },
          {
            "key": "c",
            "label": "Numerator B",
            "value": 1,
            "type": "number"
          },
          {
            "key": "d",
            "label": "Denominator B",
            "value": 3,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/fractions/run",
      "api": {
        "id": "fractions",
        "name": "Fractions",
        "category": "calculators",
        "description": "Add, subtract, multiply, or divide two fractions.",
        "notes": "",
        "human_path": "/en/calculators/fractions/",
        "method": "POST",
        "endpoint": "/api/v1/tools/fractions/run",
        "schema_url": "/api/v1/tools/fractions",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "a": {
                  "type": "number",
                  "description": "Numerator A",
                  "default": 1.0
                },
                "b": {
                  "type": "number",
                  "description": "Denominator A",
                  "default": 2.0
                },
                "op": {
                  "type": "string",
                  "description": "Operation",
                  "default": "+",
                  "enum": [
                    "+",
                    "-",
                    "×",
                    "÷"
                  ]
                },
                "c": {
                  "type": "number",
                  "description": "Numerator B",
                  "default": 1.0
                },
                "d": {
                  "type": "number",
                  "description": "Denominator B",
                  "default": 3.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/calculators/fractions/",
      "agent_url": "https://happytails.ai/agents/en/calculators/fractions/"
    },
    {
      "id": "lcm",
      "category": "calculators",
      "built": true,
      "requirements": "Positive-integer domain, step explanation and exact arithmetic.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Whole numbers",
          "placeholder": "4, 6",
          "help": "Separate positive whole numbers with commas, spaces or new lines. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/lcm/run",
      "api": {
        "id": "lcm",
        "name": "Lcm",
        "category": "calculators",
        "description": "Find the least common multiple of whole numbers.",
        "notes": "",
        "human_path": "/en/calculators/lcm/",
        "method": "POST",
        "endpoint": "/api/v1/tools/lcm/run",
        "schema_url": "/api/v1/tools/lcm",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/calculators/lcm/",
      "agent_url": "https://happytails.ai/agents/en/calculators/lcm/"
    },
    {
      "id": "margin",
      "category": "calculators",
      "built": true,
      "requirements": "Revenue and cost; distinguish gross margin from markup and specify zero/negative handling.",
      "implementation": {
        "fields": [
          {
            "key": "cost",
            "label": "Cost",
            "value": 60,
            "type": "number"
          },
          {
            "key": "price",
            "label": "Selling price",
            "value": 100,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/margin/run",
      "api": {
        "id": "margin",
        "name": "Margin",
        "category": "calculators",
        "description": "Calculate profit and profit margin from cost and selling price.",
        "notes": "",
        "human_path": "/en/calculators/margin/",
        "method": "POST",
        "endpoint": "/api/v1/tools/margin/run",
        "schema_url": "/api/v1/tools/margin",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "cost": {
                  "type": "number",
                  "description": "Cost",
                  "default": 60.0
                },
                "price": {
                  "type": "number",
                  "description": "Selling price",
                  "default": 100.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/calculators/margin/",
      "agent_url": "https://happytails.ai/agents/en/calculators/margin/"
    },
    {
      "id": "markup",
      "category": "calculators",
      "built": true,
      "requirements": "Cost-based markup versus revenue-based margin; show formulas and reverse calculation.",
      "implementation": {
        "fields": [
          {
            "key": "cost",
            "label": "Cost",
            "value": 60,
            "type": "number"
          },
          {
            "key": "price",
            "label": "Selling price",
            "value": 100,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/markup/run",
      "api": {
        "id": "markup",
        "name": "Markup",
        "category": "calculators",
        "description": "Calculate profit and markup from cost and selling price.",
        "notes": "",
        "human_path": "/en/calculators/markup/",
        "method": "POST",
        "endpoint": "/api/v1/tools/markup/run",
        "schema_url": "/api/v1/tools/markup",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "cost": {
                  "type": "number",
                  "description": "Cost",
                  "default": 60.0
                },
                "price": {
                  "type": "number",
                  "description": "Selling price",
                  "default": 100.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/calculators/markup/",
      "agent_url": "https://happytails.ai/agents/en/calculators/markup/"
    },
    {
      "id": "percentage",
      "category": "calculators",
      "built": true,
      "requirements": "Separate percentage-of, what-percent and increase modes; explain denominator and zero cases.",
      "implementation": {
        "fields": [
          {
            "key": "p",
            "label": "Percentage",
            "value": 10,
            "type": "number"
          },
          {
            "key": "v",
            "label": "Of value",
            "value": 200,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/percentage/run",
      "api": {
        "id": "percentage",
        "name": "Percentage",
        "category": "calculators",
        "description": "Find a percentage of a number.",
        "notes": "",
        "human_path": "/en/calculators/percentage/",
        "method": "POST",
        "endpoint": "/api/v1/tools/percentage/run",
        "schema_url": "/api/v1/tools/percentage",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "p": {
                  "type": "number",
                  "description": "Percentage",
                  "default": 10.0
                },
                "v": {
                  "type": "number",
                  "description": "Of value",
                  "default": 200.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/calculators/percentage/",
      "agent_url": "https://happytails.ai/agents/en/calculators/percentage/"
    },
    {
      "id": "percentage-change",
      "category": "calculators",
      "built": true,
      "requirements": "Signed change versus absolute percentage difference; zero and negative baselines explained.",
      "implementation": {
        "fields": [
          {
            "key": "a",
            "label": "Original",
            "value": 100,
            "type": "number"
          },
          {
            "key": "b",
            "label": "New",
            "value": 120,
            "type": "number"
          }
        ],
        "input": false,
        "note": "Result is percentage change; an original value of zero is undefined.",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/percentage-change/run",
      "api": {
        "id": "percentage-change",
        "name": "Percentage change",
        "category": "calculators",
        "description": "Calculate the percentage increase or decrease between two values.",
        "notes": "Result is percentage change; an original value of zero is undefined.",
        "human_path": "/en/calculators/percentage-change/",
        "method": "POST",
        "endpoint": "/api/v1/tools/percentage-change/run",
        "schema_url": "/api/v1/tools/percentage-change",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "a": {
                  "type": "number",
                  "description": "Original",
                  "default": 100.0
                },
                "b": {
                  "type": "number",
                  "description": "New",
                  "default": 120.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/calculators/percentage-change/",
      "agent_url": "https://happytails.ai/agents/en/calculators/percentage-change/"
    },
    {
      "id": "random-number",
      "category": "calculators",
      "built": true,
      "requirements": "Bounds, count and uniqueness; uniform sampling without modulo bias.",
      "implementation": {
        "fields": [
          {
            "key": "min",
            "label": "Minimum",
            "value": 1,
            "type": "number"
          },
          {
            "key": "max",
            "label": "Maximum",
            "value": 100,
            "type": "number"
          },
          {
            "key": "n",
            "label": "How many",
            "value": 1,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": false,
        "presentation": "metrics",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/random-number/run",
      "api": {
        "id": "random-number",
        "name": "Random number",
        "category": "calculators",
        "description": "Generate random whole numbers within an inclusive range.",
        "notes": "",
        "human_path": "/en/calculators/random-number/",
        "method": "POST",
        "endpoint": "/api/v1/tools/random-number/run",
        "schema_url": "/api/v1/tools/random-number",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "min": {
                  "type": "number",
                  "description": "Minimum",
                  "default": 1.0
                },
                "max": {
                  "type": "number",
                  "description": "Maximum",
                  "default": 100.0
                },
                "n": {
                  "type": "number",
                  "description": "How many",
                  "default": 1.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/calculators/random-number/",
      "agent_url": "https://happytails.ai/agents/en/calculators/random-number/"
    },
    {
      "id": "ratio",
      "category": "calculators",
      "built": true,
      "requirements": "Simplify integer ratios and scale proportions; decimal/zero rules and explicit rounding.",
      "implementation": {
        "fields": [
          {
            "key": "a",
            "label": "First amount",
            "value": 12,
            "type": "number"
          },
          {
            "key": "b",
            "label": "Second amount",
            "value": 18,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/ratio/run",
      "api": {
        "id": "ratio",
        "name": "Ratio",
        "category": "calculators",
        "description": "Simplify a ratio of two whole numbers.",
        "notes": "",
        "human_path": "/en/calculators/ratio/",
        "method": "POST",
        "endpoint": "/api/v1/tools/ratio/run",
        "schema_url": "/api/v1/tools/ratio",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "a": {
                  "type": "number",
                  "description": "First amount",
                  "default": 12.0
                },
                "b": {
                  "type": "number",
                  "description": "Second amount",
                  "default": 18.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/calculators/ratio/",
      "agent_url": "https://happytails.ai/agents/en/calculators/ratio/"
    },
    {
      "id": "rounding",
      "category": "calculators",
      "built": true,
      "requirements": "Decimal places, significant figures and explicit rounding conventions.",
      "implementation": {
        "fields": [
          {
            "key": "value",
            "label": "Value",
            "value": 3.14159,
            "type": "number"
          },
          {
            "key": "places",
            "label": "Decimal places",
            "value": 2,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/rounding/run",
      "api": {
        "id": "rounding",
        "name": "Rounding",
        "category": "calculators",
        "description": "Round a number to a chosen number of decimal places.",
        "notes": "",
        "human_path": "/en/calculators/rounding/",
        "method": "POST",
        "endpoint": "/api/v1/tools/rounding/run",
        "schema_url": "/api/v1/tools/rounding",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "value": {
                  "type": "number",
                  "description": "Value",
                  "default": 3.14159
                },
                "places": {
                  "type": "number",
                  "description": "Decimal places",
                  "default": 2.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/calculators/rounding/",
      "agent_url": "https://happytails.ai/agents/en/calculators/rounding/"
    },
    {
      "id": "scientific-notation",
      "category": "calculators",
      "built": true,
      "requirements": "Convert and calculate with exponents; explain precision and overflow.",
      "implementation": {
        "fields": [
          {
            "key": "value",
            "label": "Value",
            "value": 123456,
            "type": "number"
          },
          {
            "key": "places",
            "label": "Decimal places",
            "value": 4,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/scientific-notation/run",
      "api": {
        "id": "scientific-notation",
        "name": "Scientific notation",
        "category": "calculators",
        "description": "Write a number in scientific notation.",
        "notes": "",
        "human_path": "/en/calculators/scientific-notation/",
        "method": "POST",
        "endpoint": "/api/v1/tools/scientific-notation/run",
        "schema_url": "/api/v1/tools/scientific-notation",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "value": {
                  "type": "number",
                  "description": "Value",
                  "default": 123456.0
                },
                "places": {
                  "type": "number",
                  "description": "Decimal places",
                  "default": 4.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/calculators/scientific-notation/",
      "agent_url": "https://happytails.ai/agents/en/calculators/scientific-notation/"
    },
    {
      "id": "square-footage",
      "category": "calculators",
      "built": true,
      "requirements": "Room shapes, multiple areas and chosen units; clear dimension labels.",
      "implementation": {
        "fields": [
          {
            "key": "length",
            "label": "Length (feet)",
            "value": 12,
            "type": "number"
          },
          {
            "key": "width",
            "label": "Width (feet)",
            "value": 10,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/square-footage/run",
      "api": {
        "id": "square-footage",
        "name": "Square footage",
        "category": "calculators",
        "description": "Calculate rectangular floor area in square feet and square meters.",
        "notes": "",
        "human_path": "/en/calculators/square-footage/",
        "method": "POST",
        "endpoint": "/api/v1/tools/square-footage/run",
        "schema_url": "/api/v1/tools/square-footage",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "length": {
                  "type": "number",
                  "description": "Length (feet)",
                  "default": 12.0
                },
                "width": {
                  "type": "number",
                  "description": "Width (feet)",
                  "default": 10.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/calculators/square-footage/",
      "agent_url": "https://happytails.ai/agents/en/calculators/square-footage/"
    },
    {
      "id": "standard-deviation",
      "category": "calculators",
      "built": true,
      "requirements": "Population versus sample formulas, data count and rounding; input examples.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Numbers",
          "placeholder": "2, 4, 6",
          "help": "Separate numbers with commas, spaces or new lines. Choose sample or population in the settings. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/standard-deviation/run",
      "api": {
        "id": "standard-deviation",
        "name": "Standard deviation",
        "category": "calculators",
        "description": "Calculate the mean and standard deviation of a set of numbers.",
        "notes": "",
        "human_path": "/en/calculators/standard-deviation/",
        "method": "POST",
        "endpoint": "/api/v1/tools/standard-deviation/run",
        "schema_url": "/api/v1/tools/standard-deviation",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/calculators/standard-deviation/",
      "agent_url": "https://happytails.ai/agents/en/calculators/standard-deviation/"
    },
    {
      "id": "tip",
      "category": "calculators",
      "built": true,
      "requirements": "Bill split, tip basis and rounding; currency is a display choice, not FX conversion.",
      "implementation": {
        "fields": [
          {
            "key": "bill",
            "label": "Bill",
            "value": 100,
            "type": "number"
          },
          {
            "key": "tip",
            "label": "Tip (%)",
            "value": 15,
            "type": "number"
          },
          {
            "key": "people",
            "label": "People",
            "value": 2,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/tip/run",
      "api": {
        "id": "tip",
        "name": "Tip",
        "category": "calculators",
        "description": "Calculate a tip, the total bill, and each person’s share.",
        "notes": "",
        "human_path": "/en/calculators/tip/",
        "method": "POST",
        "endpoint": "/api/v1/tools/tip/run",
        "schema_url": "/api/v1/tools/tip",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "bill": {
                  "type": "number",
                  "description": "Bill",
                  "default": 100.0
                },
                "tip": {
                  "type": "number",
                  "description": "Tip (%)",
                  "default": 15.0
                },
                "people": {
                  "type": "number",
                  "description": "People",
                  "default": 2.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/calculators/tip/",
      "agent_url": "https://happytails.ai/agents/en/calculators/tip/"
    },
    {
      "id": "triangle",
      "category": "calculators",
      "built": true,
      "requirements": "Validate triangle constraints and ambiguous angle/side cases.",
      "implementation": {
        "fields": [
          {
            "key": "a",
            "label": "Side a",
            "value": 3,
            "type": "number"
          },
          {
            "key": "b",
            "label": "Side b",
            "value": 4,
            "type": "number"
          },
          {
            "key": "c",
            "label": "Side c",
            "value": 5,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/triangle/run",
      "api": {
        "id": "triangle",
        "name": "Triangle",
        "category": "calculators",
        "description": "Calculate a triangle’s perimeter and area from its three side lengths.",
        "notes": "",
        "human_path": "/en/calculators/triangle/",
        "method": "POST",
        "endpoint": "/api/v1/tools/triangle/run",
        "schema_url": "/api/v1/tools/triangle",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "a": {
                  "type": "number",
                  "description": "Side a",
                  "default": 3.0
                },
                "b": {
                  "type": "number",
                  "description": "Side b",
                  "default": 4.0
                },
                "c": {
                  "type": "number",
                  "description": "Side c",
                  "default": 5.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/calculators/triangle/",
      "agent_url": "https://happytails.ai/agents/en/calculators/triangle/"
    },
    {
      "id": "volume-calculator",
      "category": "calculators",
      "built": true,
      "requirements": "Shape-specific dimensions and formulas; do not mix with unit conversion.",
      "implementation": {
        "fields": [
          {
            "key": "shape",
            "label": "Shape",
            "value": "Box",
            "type": "select",
            "values": [
              "Box",
              "Cylinder",
              "Sphere"
            ]
          },
          {
            "key": "a",
            "label": "Length or radius",
            "value": 3,
            "type": "number"
          },
          {
            "key": "b",
            "label": "Width or cylinder height",
            "value": 4,
            "type": "number"
          },
          {
            "key": "c",
            "label": "Box height",
            "value": 5,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/volume-calculator/run",
      "api": {
        "id": "volume-calculator",
        "name": "Volume calculator",
        "category": "calculators",
        "description": "Calculate the volume of a box, cylinder, or sphere.",
        "notes": "",
        "human_path": "/en/calculators/volume-calculator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/volume-calculator/run",
        "schema_url": "/api/v1/tools/volume-calculator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "shape": {
                  "type": "string",
                  "description": "Shape",
                  "default": "Box",
                  "enum": [
                    "Box",
                    "Cylinder",
                    "Sphere"
                  ]
                },
                "a": {
                  "type": "number",
                  "description": "Length or radius",
                  "default": 3.0
                },
                "b": {
                  "type": "number",
                  "description": "Width or cylinder height",
                  "default": 4.0
                },
                "c": {
                  "type": "number",
                  "description": "Box height",
                  "default": 5.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/calculators/volume-calculator/",
      "agent_url": "https://happytails.ai/agents/en/calculators/volume-calculator/"
    },
    {
      "id": "change-csv-delimiter",
      "category": "data-tools",
      "built": true,
      "requirements": "Parse and reserialize correctly; never blindly replace characters in quoted cells.",
      "implementation": {
        "fields": [
          {
            "key": "delimiter",
            "label": "CSV separator",
            "value": ",",
            "type": "select",
            "values": [
              ",",
              ";",
              "\t"
            ]
          },
          {
            "key": "outputDelimiter",
            "label": "Output separator",
            "value": ",",
            "type": "select",
            "values": [
              ",",
              ";",
              "\t"
            ]
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/change-csv-delimiter/run",
      "api": {
        "id": "change-csv-delimiter",
        "name": "Change CSV delimiter",
        "category": "data-tools",
        "description": "Parse and reserialize correctly.",
        "notes": "",
        "human_path": "/en/data-tools/change-csv-delimiter/",
        "method": "POST",
        "endpoint": "/api/v1/tools/change-csv-delimiter/run",
        "schema_url": "/api/v1/tools/change-csv-delimiter",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "delimiter": {
                  "type": "string",
                  "description": "CSV separator",
                  "default": ",",
                  "enum": [
                    ",",
                    ";",
                    "\t"
                  ]
                },
                "outputDelimiter": {
                  "type": "string",
                  "description": "Output separator",
                  "default": ",",
                  "enum": [
                    ",",
                    ";",
                    "\t"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/change-csv-delimiter/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/change-csv-delimiter/"
    },
    {
      "id": "csv-column-selector",
      "category": "data-tools",
      "built": true,
      "requirements": "Select/reorder columns with header preview; preserve types and export quoting.",
      "implementation": {
        "fields": [
          {
            "key": "delimiter",
            "label": "CSV separator",
            "value": ",",
            "type": "select",
            "values": [
              ",",
              ";",
              "\t"
            ]
          },
          {
            "key": "columns",
            "label": "Columns to keep (comma separated)",
            "value": "",
            "type": "text"
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "CSV",
          "placeholder": "name,score\nAda,98\nSam,92",
          "help": "Include a header row. Quote cells that contain commas or new lines. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/csv-column-selector/run",
      "api": {
        "id": "csv-column-selector",
        "name": "CSV column selector",
        "category": "data-tools",
        "description": "Keep selected CSV columns in the order you choose.",
        "notes": "",
        "human_path": "/en/data-tools/csv-column-selector/",
        "method": "POST",
        "endpoint": "/api/v1/tools/csv-column-selector/run",
        "schema_url": "/api/v1/tools/csv-column-selector",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "delimiter": {
                  "type": "string",
                  "description": "CSV separator",
                  "default": ",",
                  "enum": [
                    ",",
                    ";",
                    "\t"
                  ]
                },
                "columns": {
                  "type": "string",
                  "description": "Columns to keep (comma separated)",
                  "default": ""
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/csv-column-selector/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/csv-column-selector/"
    },
    {
      "id": "csv-remove-duplicates",
      "category": "data-tools",
      "built": true,
      "requirements": "Compare full rows or selected keys; keep-first/last and show removed-row count.",
      "implementation": {
        "fields": [
          {
            "key": "delimiter",
            "label": "CSV separator",
            "value": ",",
            "type": "select",
            "values": [
              ",",
              ";",
              "\t"
            ]
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "CSV",
          "placeholder": "name,score\nAda,98\nSam,92",
          "help": "Include a header row. Quote cells that contain commas or new lines. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/csv-remove-duplicates/run",
      "api": {
        "id": "csv-remove-duplicates",
        "name": "CSV remove duplicates",
        "category": "data-tools",
        "description": "Remove duplicate CSV rows while keeping the first occurrence.",
        "notes": "",
        "human_path": "/en/data-tools/csv-remove-duplicates/",
        "method": "POST",
        "endpoint": "/api/v1/tools/csv-remove-duplicates/run",
        "schema_url": "/api/v1/tools/csv-remove-duplicates",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "delimiter": {
                  "type": "string",
                  "description": "CSV separator",
                  "default": ",",
                  "enum": [
                    ",",
                    ";",
                    "\t"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/csv-remove-duplicates/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/csv-remove-duplicates/"
    },
    {
      "id": "csv-to-excel",
      "category": "data-tools",
      "built": true,
      "requirements": "Explicit column types, encoding and delimiter; prevent unintended formulas on export.",
      "implementation": {
        "fields": [
          {
            "key": "sheet",
            "label": "Worksheet name (blank = first)",
            "value": "",
            "type": "text"
          },
          {
            "key": "delimiter",
            "label": "CSV separator",
            "value": ",",
            "type": "select",
            "values": [
              ",",
              ";",
              "\t"
            ]
          }
        ],
        "note": "CSV cells are stored as text to preserve leading zeros and prevent formula execution. Nested JSON values become JSON strings.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "CSV",
          "placeholder": "name,score\nAda,98\nSam,92",
          "help": "Include a header row. Quote cells that contain commas or new lines. Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/csv-to-excel/run",
      "api": {
        "id": "csv-to-excel",
        "name": "CSV to excel",
        "category": "data-tools",
        "description": "Create an Excel workbook from CSV text.",
        "notes": "CSV cells are stored as text to preserve leading zeros and prevent formula execution. Nested JSON values become JSON strings.",
        "human_path": "/en/data-tools/csv-to-excel/",
        "method": "POST",
        "endpoint": "/api/v1/tools/csv-to-excel/run",
        "schema_url": "/api/v1/tools/csv-to-excel",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "sheet": {
                  "type": "string",
                  "description": "Worksheet name (blank = first)",
                  "default": ""
                },
                "delimiter": {
                  "type": "string",
                  "description": "CSV separator",
                  "default": ",",
                  "enum": [
                    ",",
                    ";",
                    "\t"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/csv-to-excel/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/csv-to-excel/"
    },
    {
      "id": "csv-to-geojson",
      "category": "data-tools",
      "built": true,
      "requirements": "Map latitude/longitude columns, validate coordinates and preserve chosen properties.",
      "implementation": {
        "fields": [
          {
            "key": "delimiter",
            "label": "CSV separator",
            "value": ",",
            "type": "select",
            "values": [
              ",",
              ";",
              "\t"
            ]
          },
          {
            "key": "lat",
            "label": "Latitude column",
            "value": "latitude",
            "type": "text"
          },
          {
            "key": "lon",
            "label": "Longitude column",
            "value": "longitude",
            "type": "text"
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "CSV",
          "placeholder": "name,score\nAda,98\nSam,92",
          "help": "Include a header row. Quote cells that contain commas or new lines. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/csv-to-geojson/run",
      "api": {
        "id": "csv-to-geojson",
        "name": "CSV to geojson",
        "category": "data-tools",
        "description": "Map latitude/longitude columns, validate coordinates and preserve chosen properties.",
        "notes": "",
        "human_path": "/en/data-tools/csv-to-geojson/",
        "method": "POST",
        "endpoint": "/api/v1/tools/csv-to-geojson/run",
        "schema_url": "/api/v1/tools/csv-to-geojson",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "delimiter": {
                  "type": "string",
                  "description": "CSV separator",
                  "default": ",",
                  "enum": [
                    ",",
                    ";",
                    "\t"
                  ]
                },
                "lat": {
                  "type": "string",
                  "description": "Latitude column",
                  "default": "latitude"
                },
                "lon": {
                  "type": "string",
                  "description": "Longitude column",
                  "default": "longitude"
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/csv-to-geojson/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/csv-to-geojson/"
    },
    {
      "id": "csv-to-html",
      "category": "data-tools",
      "built": true,
      "requirements": "Escape cell content; header/alignment options and semantic table output.",
      "implementation": {
        "fields": [
          {
            "key": "delimiter",
            "label": "CSV separator",
            "value": ",",
            "type": "select",
            "values": [
              ",",
              ";",
              "\t"
            ]
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "CSV",
          "placeholder": "name,score\nAda,98\nSam,92",
          "help": "Include a header row. Quote cells that contain commas or new lines. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/csv-to-html/run",
      "api": {
        "id": "csv-to-html",
        "name": "CSV to HTML",
        "category": "data-tools",
        "description": "Convert CSV to HTML.",
        "notes": "",
        "human_path": "/en/data-tools/csv-to-html/",
        "method": "POST",
        "endpoint": "/api/v1/tools/csv-to-html/run",
        "schema_url": "/api/v1/tools/csv-to-html",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "delimiter": {
                  "type": "string",
                  "description": "CSV separator",
                  "default": ",",
                  "enum": [
                    ",",
                    ";",
                    "\t"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/csv-to-html/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/csv-to-html/"
    },
    {
      "id": "csv-to-json",
      "category": "data-tools",
      "built": true,
      "requirements": "Detect delimiter with override; headers and type inference; preserve identifiers and leading zeros.",
      "implementation": {
        "fields": [
          {
            "key": "delimiter",
            "label": "CSV separator",
            "value": ",",
            "type": "select",
            "values": [
              ",",
              ";",
              "\t"
            ]
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "CSV",
          "placeholder": "name,score\nAda,98\nSam,92",
          "help": "Include a header row. Quote cells that contain commas or new lines. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/csv-to-json/run",
      "api": {
        "id": "csv-to-json",
        "name": "CSV to JSON",
        "category": "data-tools",
        "description": "Convert CSV to JSON.",
        "notes": "",
        "human_path": "/en/data-tools/csv-to-json/",
        "method": "POST",
        "endpoint": "/api/v1/tools/csv-to-json/run",
        "schema_url": "/api/v1/tools/csv-to-json",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "delimiter": {
                  "type": "string",
                  "description": "CSV separator",
                  "default": ",",
                  "enum": [
                    ",",
                    ";",
                    "\t"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "transform_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/csv-to-json/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/csv-to-json/"
    },
    {
      "id": "csv-to-markdown",
      "category": "data-tools",
      "built": true,
      "requirements": "Escape pipes and multiline cells; alignment controls and copy/download preview.",
      "implementation": {
        "fields": [
          {
            "key": "delimiter",
            "label": "CSV separator",
            "value": ",",
            "type": "select",
            "values": [
              ",",
              ";",
              "\t"
            ]
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "CSV",
          "placeholder": "name,score\nAda,98\nSam,92",
          "help": "Include a header row. Quote cells that contain commas or new lines. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/csv-to-markdown/run",
      "api": {
        "id": "csv-to-markdown",
        "name": "CSV to markdown",
        "category": "data-tools",
        "description": "Convert CSV to Markdown.",
        "notes": "",
        "human_path": "/en/data-tools/csv-to-markdown/",
        "method": "POST",
        "endpoint": "/api/v1/tools/csv-to-markdown/run",
        "schema_url": "/api/v1/tools/csv-to-markdown",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "delimiter": {
                  "type": "string",
                  "description": "CSV separator",
                  "default": ",",
                  "enum": [
                    ",",
                    ";",
                    "\t"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/csv-to-markdown/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/csv-to-markdown/"
    },
    {
      "id": "csv-to-pdf",
      "category": "data-tools",
      "built": true,
      "requirements": "Column widths, landscape layout and page breaks; preserve legibility.",
      "implementation": {
        "fields": [],
        "note": "Plain-text PDF export. CSV rows are rendered as text; wide tables may need a spreadsheet layout. Standard PDF font character coverage applies.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "CSV",
          "placeholder": "name,score\nAda,98\nSam,92",
          "help": "Include a header row. Quote cells that contain commas or new lines. Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/csv-to-pdf/run",
      "api": {
        "id": "csv-to-pdf",
        "name": "CSV to PDF",
        "category": "data-tools",
        "description": "Column widths, landscape layout and page breaks.",
        "notes": "Plain-text PDF export. CSV rows are rendered as text; wide tables may need a spreadsheet layout. Standard PDF font character coverage applies.",
        "human_path": "/en/data-tools/csv-to-pdf/",
        "method": "POST",
        "endpoint": "/api/v1/tools/csv-to-pdf/run",
        "schema_url": "/api/v1/tools/csv-to-pdf",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/csv-to-pdf/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/csv-to-pdf/"
    },
    {
      "id": "csv-to-sql",
      "category": "data-tools",
      "built": true,
      "requirements": "Choose SQL dialect/table name; escape identifiers and values; download only.",
      "implementation": {
        "fields": [
          {
            "key": "delimiter",
            "label": "CSV separator",
            "value": ",",
            "type": "select",
            "values": [
              ",",
              ";",
              "\t"
            ]
          },
          {
            "key": "table",
            "label": "SQL table",
            "value": "data",
            "type": "text"
          }
        ],
        "note": "ANSI-style quoted identifiers and string values. Review column types before executing SQL.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "CSV",
          "placeholder": "name,score\nAda,98\nSam,92",
          "help": "Include a header row. Quote cells that contain commas or new lines. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/csv-to-sql/run",
      "api": {
        "id": "csv-to-sql",
        "name": "CSV to SQL",
        "category": "data-tools",
        "description": "Convert CSV to SQL.",
        "notes": "ANSI-style quoted identifiers and string values. Review column types before executing SQL.",
        "human_path": "/en/data-tools/csv-to-sql/",
        "method": "POST",
        "endpoint": "/api/v1/tools/csv-to-sql/run",
        "schema_url": "/api/v1/tools/csv-to-sql",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "delimiter": {
                  "type": "string",
                  "description": "CSV separator",
                  "default": ",",
                  "enum": [
                    ",",
                    ";",
                    "\t"
                  ]
                },
                "table": {
                  "type": "string",
                  "description": "SQL table",
                  "default": "data"
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/csv-to-sql/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/csv-to-sql/"
    },
    {
      "id": "csv-to-tsv",
      "category": "data-tools",
      "built": true,
      "requirements": "Preserve tabs/newlines using an explicit escape policy.",
      "implementation": {
        "fields": [
          {
            "key": "delimiter",
            "label": "CSV separator",
            "value": ",",
            "type": "select",
            "values": [
              ",",
              ";",
              "\t"
            ]
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "CSV",
          "placeholder": "name,score\nAda,98\nSam,92",
          "help": "Include a header row. Quote cells that contain commas or new lines. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/csv-to-tsv/run",
      "api": {
        "id": "csv-to-tsv",
        "name": "CSV to TSV",
        "category": "data-tools",
        "description": "Convert CSV to TSV.",
        "notes": "",
        "human_path": "/en/data-tools/csv-to-tsv/",
        "method": "POST",
        "endpoint": "/api/v1/tools/csv-to-tsv/run",
        "schema_url": "/api/v1/tools/csv-to-tsv",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "delimiter": {
                  "type": "string",
                  "description": "CSV separator",
                  "default": ",",
                  "enum": [
                    ",",
                    ";",
                    "\t"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/csv-to-tsv/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/csv-to-tsv/"
    },
    {
      "id": "csv-to-xml",
      "category": "data-tools",
      "built": true,
      "requirements": "Choose root/row tags and sanitize invalid XML element names.",
      "implementation": {
        "fields": [
          {
            "key": "delimiter",
            "label": "CSV separator",
            "value": ",",
            "type": "select",
            "values": [
              ",",
              ";",
              "\t"
            ]
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "CSV",
          "placeholder": "name,score\nAda,98\nSam,92",
          "help": "Include a header row. Quote cells that contain commas or new lines. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/csv-to-xml/run",
      "api": {
        "id": "csv-to-xml",
        "name": "CSV to XML",
        "category": "data-tools",
        "description": "Convert CSV to XML.",
        "notes": "",
        "human_path": "/en/data-tools/csv-to-xml/",
        "method": "POST",
        "endpoint": "/api/v1/tools/csv-to-xml/run",
        "schema_url": "/api/v1/tools/csv-to-xml",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "delimiter": {
                  "type": "string",
                  "description": "CSV separator",
                  "default": ",",
                  "enum": [
                    ",",
                    ";",
                    "\t"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/csv-to-xml/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/csv-to-xml/"
    },
    {
      "id": "csv-to-yaml",
      "category": "data-tools",
      "built": true,
      "requirements": "Preserve quoted identifiers and choose scalar typing explicitly.",
      "implementation": {
        "fields": [
          {
            "key": "delimiter",
            "label": "CSV separator",
            "value": ",",
            "type": "select",
            "values": [
              ",",
              ";",
              "\t"
            ]
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "CSV",
          "placeholder": "name,score\nAda,98\nSam,92",
          "help": "Include a header row. Quote cells that contain commas or new lines. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/csv-to-yaml/run",
      "api": {
        "id": "csv-to-yaml",
        "name": "CSV to YAML",
        "category": "data-tools",
        "description": "Convert CSV to YAML.",
        "notes": "",
        "human_path": "/en/data-tools/csv-to-yaml/",
        "method": "POST",
        "endpoint": "/api/v1/tools/csv-to-yaml/run",
        "schema_url": "/api/v1/tools/csv-to-yaml",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "delimiter": {
                  "type": "string",
                  "description": "CSV separator",
                  "default": ",",
                  "enum": [
                    ",",
                    ";",
                    "\t"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/csv-to-yaml/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/csv-to-yaml/"
    },
    {
      "id": "csv-validator",
      "category": "data-tools",
      "built": true,
      "requirements": "Report malformed quoting, inconsistent row widths and encoding; configurable dialect.",
      "implementation": {
        "fields": [
          {
            "key": "delimiter",
            "label": "CSV separator",
            "value": ",",
            "type": "select",
            "values": [
              ",",
              ";",
              "\t"
            ]
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "CSV",
          "placeholder": "name,score\nAda,98\nSam,92",
          "help": "Include a header row. Quote cells that contain commas or new lines. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/csv-validator/run",
      "api": {
        "id": "csv-validator",
        "name": "CSV validator",
        "category": "data-tools",
        "description": "Check CSV headers, quoting and row lengths.",
        "notes": "",
        "human_path": "/en/data-tools/csv-validator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/csv-validator/run",
        "schema_url": "/api/v1/tools/csv-validator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "delimiter": {
                  "type": "string",
                  "description": "CSV separator",
                  "default": ",",
                  "enum": [
                    ",",
                    ";",
                    "\t"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/csv-validator/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/csv-validator/"
    },
    {
      "id": "csv-viewer",
      "category": "data-tools",
      "built": true,
      "requirements": "Virtualized preview, delimiter/encoding controls, row counts and large-file limits.",
      "implementation": {
        "fields": [
          {
            "key": "delimiter",
            "label": "CSV separator",
            "value": ",",
            "type": "select",
            "values": [
              ",",
              ";",
              "\t"
            ]
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "CSV",
          "placeholder": "name,score\nAda,98\nSam,92",
          "help": "Include a header row. Quote cells that contain commas or new lines. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/csv-viewer/run",
      "api": {
        "id": "csv-viewer",
        "name": "CSV viewer",
        "category": "data-tools",
        "description": "Preview CSV rows and columns in a readable table.",
        "notes": "",
        "human_path": "/en/data-tools/csv-viewer/",
        "method": "POST",
        "endpoint": "/api/v1/tools/csv-viewer/run",
        "schema_url": "/api/v1/tools/csv-viewer",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "delimiter": {
                  "type": "string",
                  "description": "CSV separator",
                  "default": ",",
                  "enum": [
                    ",",
                    ";",
                    "\t"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/csv-viewer/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/csv-viewer/"
    },
    {
      "id": "excel-to-csv",
      "category": "data-tools",
      "built": true,
      "requirements": "Select sheet; explain cached formula values versus recalculation; preserve dates and IDs explicitly.",
      "implementation": {
        "fields": [
          {
            "key": "sheet",
            "label": "Worksheet name (blank = first)",
            "value": "",
            "type": "text"
          },
          {
            "key": "delimiter",
            "label": "CSV separator",
            "value": ",",
            "type": "select",
            "values": [
              ",",
              ";",
              "\t"
            ]
          }
        ],
        "files": true,
        "input": false,
        "accept": ".xlsx,.xls,.ods",
        "note": "Uses stored cell values; formulas are not recalculated. Check dates, identifiers and cached formula results. CSV/JSON export reads one worksheet.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/excel-to-csv/run",
      "api": {
        "id": "excel-to-csv",
        "name": "Excel to CSV",
        "category": "data-tools",
        "description": "Select sheet.",
        "notes": "Uses stored cell values; formulas are not recalculated. Check dates, identifiers and cached formula results. CSV/JSON export reads one worksheet.",
        "human_path": "/en/data-tools/excel-to-csv/",
        "method": "POST",
        "endpoint": "/api/v1/tools/excel-to-csv/run",
        "schema_url": "/api/v1/tools/excel-to-csv",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "sheet": {
                  "type": "string",
                  "description": "Worksheet name (blank = first)",
                  "default": ""
                },
                "delimiter": {
                  "type": "string",
                  "description": "CSV separator",
                  "default": ",",
                  "enum": [
                    ",",
                    ";",
                    "\t"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/excel-to-csv/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/excel-to-csv/"
    },
    {
      "id": "excel-to-json",
      "category": "data-tools",
      "built": true,
      "requirements": "Sheet/range selection, header rows and cached formula value behavior.",
      "implementation": {
        "fields": [
          {
            "key": "sheet",
            "label": "Worksheet name (blank = first)",
            "value": "",
            "type": "text"
          }
        ],
        "files": true,
        "input": false,
        "accept": ".xlsx,.xls,.ods",
        "note": "Uses stored cell values; formulas are not recalculated. Check dates, identifiers and cached formula results. CSV/JSON export reads one worksheet.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/excel-to-json/run",
      "api": {
        "id": "excel-to-json",
        "name": "Excel to JSON",
        "category": "data-tools",
        "description": "Sheet/range selection, header rows and cached formula value behavior.",
        "notes": "Uses stored cell values; formulas are not recalculated. Check dates, identifiers and cached formula results. CSV/JSON export reads one worksheet.",
        "human_path": "/en/data-tools/excel-to-json/",
        "method": "POST",
        "endpoint": "/api/v1/tools/excel-to-json/run",
        "schema_url": "/api/v1/tools/excel-to-json",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "sheet": {
                  "type": "string",
                  "description": "Worksheet name (blank = first)",
                  "default": ""
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/excel-to-json/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/excel-to-json/"
    },
    {
      "id": "geojson-to-csv",
      "category": "data-tools",
      "built": true,
      "requirements": "Define supported geometry flattening and property collisions.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "GeoJSON",
          "placeholder": "{\"type\":\"FeatureCollection\",\"features\":[]}",
          "help": "Paste a valid GeoJSON object. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/geojson-to-csv/run",
      "api": {
        "id": "geojson-to-csv",
        "name": "Geojson to CSV",
        "category": "data-tools",
        "description": "Define supported geometry flattening and property collisions.",
        "notes": "",
        "human_path": "/en/data-tools/geojson-to-csv/",
        "method": "POST",
        "endpoint": "/api/v1/tools/geojson-to-csv/run",
        "schema_url": "/api/v1/tools/geojson-to-csv",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/geojson-to-csv/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/geojson-to-csv/"
    },
    {
      "id": "html-table-to-csv",
      "category": "data-tools",
      "built": true,
      "requirements": "Pasted HTML only initially; define rowspan/colspan flattening.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "HTML source",
          "placeholder": "<p>Hello <strong>world</strong>.</p>",
          "help": "Paste HTML markup, not a website URL. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/html-table-to-csv/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/html-table-to-csv/"
    },
    {
      "id": "json-to-csv",
      "category": "data-tools",
      "built": true,
      "requirements": "Define nested-array flattening, null handling and column order; protect spreadsheet exports.",
      "implementation": {
        "fields": [
          {
            "key": "delimiter",
            "label": "CSV separator",
            "value": ",",
            "type": "select",
            "values": [
              ",",
              ";",
              "\t"
            ]
          },
          {
            "key": "safe",
            "label": "Protect spreadsheet formulas",
            "value": true,
            "type": "checkbox"
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "JSON",
          "placeholder": "{\"name\":\"Ada\",\"count\":2}",
          "help": "Use double-quoted property names and valid JSON values. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/json-to-csv/run",
      "api": {
        "id": "json-to-csv",
        "name": "JSON to CSV",
        "category": "data-tools",
        "description": "Convert JSON to CSV.",
        "notes": "",
        "human_path": "/en/data-tools/json-to-csv/",
        "method": "POST",
        "endpoint": "/api/v1/tools/json-to-csv/run",
        "schema_url": "/api/v1/tools/json-to-csv",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "delimiter": {
                  "type": "string",
                  "description": "CSV separator",
                  "default": ",",
                  "enum": [
                    ",",
                    ";",
                    "\t"
                  ]
                },
                "safe": {
                  "type": "boolean",
                  "description": "Protect spreadsheet formulas",
                  "default": true
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "transform_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/json-to-csv/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/json-to-csv/"
    },
    {
      "id": "json-to-excel",
      "category": "data-tools",
      "built": true,
      "requirements": "Flatten records, select columns and preserve identifiers and dates.",
      "implementation": {
        "fields": [
          {
            "key": "sheet",
            "label": "Worksheet name (blank = first)",
            "value": "",
            "type": "text"
          },
          {
            "key": "delimiter",
            "label": "CSV separator",
            "value": ",",
            "type": "select",
            "values": [
              ",",
              ";",
              "\t"
            ]
          }
        ],
        "note": "CSV cells are stored as text to preserve leading zeros and prevent formula execution. Nested JSON values become JSON strings.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "JSON",
          "placeholder": "{\"name\":\"Ada\",\"count\":2}",
          "help": "Use double-quoted property names and valid JSON values. Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/json-to-excel/run",
      "api": {
        "id": "json-to-excel",
        "name": "JSON to excel",
        "category": "data-tools",
        "description": "Flatten records, select columns and preserve identifiers and dates.",
        "notes": "CSV cells are stored as text to preserve leading zeros and prevent formula execution. Nested JSON values become JSON strings.",
        "human_path": "/en/data-tools/json-to-excel/",
        "method": "POST",
        "endpoint": "/api/v1/tools/json-to-excel/run",
        "schema_url": "/api/v1/tools/json-to-excel",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "sheet": {
                  "type": "string",
                  "description": "Worksheet name (blank = first)",
                  "default": ""
                },
                "delimiter": {
                  "type": "string",
                  "description": "CSV separator",
                  "default": ",",
                  "enum": [
                    ",",
                    ";",
                    "\t"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/json-to-excel/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/json-to-excel/"
    },
    {
      "id": "json-to-html",
      "category": "data-tools",
      "built": true,
      "requirements": "Choose record path and columns; escape cell HTML; nested-data policy.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "JSON",
          "placeholder": "{\"name\":\"Ada\",\"count\":2}",
          "help": "Use double-quoted property names and valid JSON values. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/json-to-html/run",
      "api": {
        "id": "json-to-html",
        "name": "JSON to HTML",
        "category": "data-tools",
        "description": "Convert JSON to HTML.",
        "notes": "",
        "human_path": "/en/data-tools/json-to-html/",
        "method": "POST",
        "endpoint": "/api/v1/tools/json-to-html/run",
        "schema_url": "/api/v1/tools/json-to-html",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/json-to-html/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/json-to-html/"
    },
    {
      "id": "json-to-jsonl",
      "category": "data-tools",
      "built": true,
      "requirements": "Array-to-lines with one valid JSON value per line; clarify NDJSON alias.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "JSON",
          "placeholder": "{\"name\":\"Ada\",\"count\":2}",
          "help": "Use double-quoted property names and valid JSON values. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/json-to-jsonl/run",
      "api": {
        "id": "json-to-jsonl",
        "name": "JSON to jsonl",
        "category": "data-tools",
        "description": "Convert JSON to JSON Lines.",
        "notes": "",
        "human_path": "/en/data-tools/json-to-jsonl/",
        "method": "POST",
        "endpoint": "/api/v1/tools/json-to-jsonl/run",
        "schema_url": "/api/v1/tools/json-to-jsonl",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/json-to-jsonl/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/json-to-jsonl/"
    },
    {
      "id": "json-to-markdown",
      "category": "data-tools",
      "built": true,
      "requirements": "Tabular objects only; handle nested values and escape Markdown pipes.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "JSON",
          "placeholder": "{\"name\":\"Ada\",\"count\":2}",
          "help": "Use double-quoted property names and valid JSON values. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/json-to-markdown/run",
      "api": {
        "id": "json-to-markdown",
        "name": "JSON to markdown",
        "category": "data-tools",
        "description": "Convert JSON to Markdown.",
        "notes": "",
        "human_path": "/en/data-tools/json-to-markdown/",
        "method": "POST",
        "endpoint": "/api/v1/tools/json-to-markdown/run",
        "schema_url": "/api/v1/tools/json-to-markdown",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/json-to-markdown/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/json-to-markdown/"
    },
    {
      "id": "json-to-sql",
      "category": "data-tools",
      "built": true,
      "requirements": "SQL dialect, table name and escaped literals; no execution; infer column types transparently.",
      "implementation": {
        "fields": [
          {
            "key": "delimiter",
            "label": "CSV separator",
            "value": ",",
            "type": "select",
            "values": [
              ",",
              ";",
              "\t"
            ]
          },
          {
            "key": "table",
            "label": "SQL table",
            "value": "data",
            "type": "text"
          }
        ],
        "note": "ANSI-style quoted identifiers and string values. Review column types before executing SQL.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "JSON",
          "placeholder": "{\"name\":\"Ada\",\"count\":2}",
          "help": "Use double-quoted property names and valid JSON values. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/json-to-sql/run",
      "api": {
        "id": "json-to-sql",
        "name": "JSON to SQL",
        "category": "data-tools",
        "description": "Convert JSON to SQL.",
        "notes": "ANSI-style quoted identifiers and string values. Review column types before executing SQL.",
        "human_path": "/en/data-tools/json-to-sql/",
        "method": "POST",
        "endpoint": "/api/v1/tools/json-to-sql/run",
        "schema_url": "/api/v1/tools/json-to-sql",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "delimiter": {
                  "type": "string",
                  "description": "CSV separator",
                  "default": ",",
                  "enum": [
                    ",",
                    ";",
                    "\t"
                  ]
                },
                "table": {
                  "type": "string",
                  "description": "SQL table",
                  "default": "data"
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/json-to-sql/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/json-to-sql/"
    },
    {
      "id": "json-to-toml",
      "category": "data-tools",
      "built": true,
      "requirements": "Document unsupported null/heterogeneous values and TOML version.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "JSON",
          "placeholder": "{\"name\":\"Ada\",\"count\":2}",
          "help": "Use double-quoted property names and valid JSON values. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/json-to-toml/run",
      "api": {
        "id": "json-to-toml",
        "name": "JSON to TOML",
        "category": "data-tools",
        "description": "Convert JSON to TOML.",
        "notes": "",
        "human_path": "/en/data-tools/json-to-toml/",
        "method": "POST",
        "endpoint": "/api/v1/tools/json-to-toml/run",
        "schema_url": "/api/v1/tools/json-to-toml",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/json-to-toml/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/json-to-toml/"
    },
    {
      "id": "json-to-tsv",
      "category": "data-tools",
      "built": true,
      "requirements": "Array path selection, flattening and quoting; reject unrepresentable nested shapes unless policy chosen.",
      "implementation": {
        "fields": [
          {
            "key": "delimiter",
            "label": "CSV separator",
            "value": ",",
            "type": "select",
            "values": [
              ",",
              ";",
              "\t"
            ]
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "JSON",
          "placeholder": "{\"name\":\"Ada\",\"count\":2}",
          "help": "Use double-quoted property names and valid JSON values. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/json-to-tsv/run",
      "api": {
        "id": "json-to-tsv",
        "name": "JSON to TSV",
        "category": "data-tools",
        "description": "Convert JSON to TSV.",
        "notes": "",
        "human_path": "/en/data-tools/json-to-tsv/",
        "method": "POST",
        "endpoint": "/api/v1/tools/json-to-tsv/run",
        "schema_url": "/api/v1/tools/json-to-tsv",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "delimiter": {
                  "type": "string",
                  "description": "CSV separator",
                  "default": ",",
                  "enum": [
                    ",",
                    ";",
                    "\t"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/json-to-tsv/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/json-to-tsv/"
    },
    {
      "id": "json-to-xml",
      "category": "data-tools",
      "built": true,
      "requirements": "Explicit array/root/attribute mapping and invalid tag-name handling.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "JSON",
          "placeholder": "{\"name\":\"Ada\",\"count\":2}",
          "help": "Use double-quoted property names and valid JSON values. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/json-to-xml/run",
      "api": {
        "id": "json-to-xml",
        "name": "JSON to XML",
        "category": "data-tools",
        "description": "Convert JSON to XML.",
        "notes": "",
        "human_path": "/en/data-tools/json-to-xml/",
        "method": "POST",
        "endpoint": "/api/v1/tools/json-to-xml/run",
        "schema_url": "/api/v1/tools/json-to-xml",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/json-to-xml/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/json-to-xml/"
    },
    {
      "id": "json-to-yaml",
      "category": "data-tools",
      "built": true,
      "requirements": "Define scalar typing and formatting; do not suggest lossless preservation of comments.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "JSON",
          "placeholder": "{\"name\":\"Ada\",\"count\":2}",
          "help": "Use double-quoted property names and valid JSON values. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/json-to-yaml/run",
      "api": {
        "id": "json-to-yaml",
        "name": "JSON to YAML",
        "category": "data-tools",
        "description": "Convert JSON to YAML.",
        "notes": "",
        "human_path": "/en/data-tools/json-to-yaml/",
        "method": "POST",
        "endpoint": "/api/v1/tools/json-to-yaml/run",
        "schema_url": "/api/v1/tools/json-to-yaml",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/json-to-yaml/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/json-to-yaml/"
    },
    {
      "id": "jsonl-to-json",
      "category": "data-tools",
      "built": true,
      "requirements": "Line-numbered errors and streaming limits; distinguish arrays from multiple JSON values.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "JSON Lines",
          "placeholder": "{\"name\":\"Ada\"}\n{\"name\":\"Sam\"}",
          "help": "Enter one complete JSON object per line. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/jsonl-to-json/run",
      "api": {
        "id": "jsonl-to-json",
        "name": "Jsonl to JSON",
        "category": "data-tools",
        "description": "Convert JSON Lines into a JSON array.",
        "notes": "",
        "human_path": "/en/data-tools/jsonl-to-json/",
        "method": "POST",
        "endpoint": "/api/v1/tools/jsonl-to-json/run",
        "schema_url": "/api/v1/tools/jsonl-to-json",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/jsonl-to-json/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/jsonl-to-json/"
    },
    {
      "id": "semantic-deduplication",
      "category": "data-tools",
      "built": true,
      "requirements": "Group near-duplicate text rows in uploaded CSV; set similarity threshold; review proposed groups before export; never automatically discard records based only on embeddings.",
      "implementation": {
        "fields": [
          {
            "key": "column",
            "label": "Text column name",
            "type": "text",
            "value": "text"
          },
          {
            "key": "threshold",
            "label": "Similarity threshold",
            "type": "number",
            "value": 0.85,
            "min": 0.5,
            "max": 1
          }
        ],
        "files": true,
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "extra": true,
        "maxFileBytes": 20971520,
        "accept": ".csv",
        "note": "Local MiniLM embeddings propose similarity groups. At most 500 rows with 1,000 characters per text value. All rows are retained for review; no automatic deletion.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/semantic-deduplication/run",
      "api": {
        "id": "semantic-deduplication",
        "name": "Semantic deduplication",
        "category": "data-tools",
        "description": "Local MiniLM embeddings propose similarity groups.",
        "notes": "Local MiniLM embeddings propose similarity groups. At most 500 rows with 1,000 characters per text value. All rows are retained for review; no automatic deletion.",
        "human_path": "/en/data-tools/semantic-deduplication/",
        "method": "POST",
        "endpoint": "/api/v1/tools/semantic-deduplication/run",
        "schema_url": "/api/v1/tools/semantic-deduplication",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "column": {
                  "type": "string",
                  "description": "Text column name",
                  "default": "text"
                },
                "threshold": {
                  "type": "number",
                  "description": "Similarity threshold",
                  "default": 0.85,
                  "minimum": 0.5,
                  "maximum": 1
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/semantic-deduplication/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/semantic-deduplication/"
    },
    {
      "id": "split-csv",
      "category": "data-tools",
      "built": true,
      "requirements": "Split by rows/size with headers repeated; quote-aware streaming.",
      "implementation": {
        "fields": [
          {
            "key": "delimiter",
            "label": "CSV separator",
            "value": ",",
            "type": "select",
            "values": [
              ",",
              ";",
              "\t"
            ]
          },
          {
            "key": "size",
            "label": "Rows per split file",
            "value": 1000,
            "type": "number"
          }
        ],
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/split-csv/run",
      "api": {
        "id": "split-csv",
        "name": "Split CSV",
        "category": "data-tools",
        "description": "Split CSV text into smaller files with repeated headers.",
        "notes": "",
        "human_path": "/en/data-tools/split-csv/",
        "method": "POST",
        "endpoint": "/api/v1/tools/split-csv/run",
        "schema_url": "/api/v1/tools/split-csv",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "delimiter": {
                  "type": "string",
                  "description": "CSV separator",
                  "default": ",",
                  "enum": [
                    ",",
                    ";",
                    "\t"
                  ]
                },
                "size": {
                  "type": "number",
                  "description": "Rows per split file",
                  "default": 1000.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/split-csv/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/split-csv/"
    },
    {
      "id": "sql-to-csv",
      "category": "data-tools",
      "built": true,
      "requirements": "Parse a declared INSERT syntax subset; never execute uploaded SQL.",
      "implementation": {
        "fields": [],
        "note": "Parses literal MySQL-style INSERT statements. Does not execute SQL or connect to a database.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "SQL",
          "placeholder": "SELECT id, name FROM users;",
          "help": "Paste SQL source. This tool does not connect to a database. Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/sql-to-csv/run",
      "api": {
        "id": "sql-to-csv",
        "name": "SQL to CSV",
        "category": "data-tools",
        "description": "Convert SQL to CSV.",
        "notes": "Parses literal MySQL-style INSERT statements. Does not execute SQL or connect to a database.",
        "human_path": "/en/data-tools/sql-to-csv/",
        "method": "POST",
        "endpoint": "/api/v1/tools/sql-to-csv/run",
        "schema_url": "/api/v1/tools/sql-to-csv",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/sql-to-csv/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/sql-to-csv/"
    },
    {
      "id": "text-classifier",
      "category": "data-tools",
      "built": true,
      "requirements": "Categorize supplied text rows using user-defined labels and examples; include uncertain category and editable results; preserve row IDs; do not treat model scores as calibrated probabilities.",
      "implementation": {
        "fields": [
          {
            "key": "labels",
            "label": "Category labels, separated by commas",
            "type": "text",
            "value": "positive, negative, neutral"
          }
        ],
        "files": false,
        "accept": "",
        "multiple": false,
        "input": true,
        "processing": "Server required",
        "native": true,
        "ai": true,
        "maxFileBytes": 20971520,
        "note": "Runs with local model weights on this website’s server. No external AI API is used. Review the result for errors. One text item per line. Review uncertain classifications.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/text-classifier/run",
      "api": {
        "id": "text-classifier",
        "name": "Text classifier",
        "category": "data-tools",
        "description": "Assign your chosen labels to each line of text.",
        "notes": "Runs with local model weights on this website’s server. No external AI API is used. Review the result for errors. One text item per line. Review uncertain classifications.",
        "human_path": "/en/data-tools/text-classifier/",
        "method": "POST",
        "endpoint": "/api/v1/tools/text-classifier/run",
        "schema_url": "/api/v1/tools/text-classifier",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "labels": {
                  "type": "string",
                  "description": "Category labels, separated by commas",
                  "default": "positive, negative, neutral"
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 0,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/text-classifier/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/text-classifier/"
    },
    {
      "id": "toml-to-json",
      "category": "data-tools",
      "built": true,
      "requirements": "Preserve date/time semantics explicitly; avoid accidental precision loss.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "TOML",
          "placeholder": "name = \"Ada\"",
          "help": "Use TOML key-value pairs. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/toml-to-json/run",
      "api": {
        "id": "toml-to-json",
        "name": "TOML to JSON",
        "category": "data-tools",
        "description": "Convert TOML to JSON.",
        "notes": "",
        "human_path": "/en/data-tools/toml-to-json/",
        "method": "POST",
        "endpoint": "/api/v1/tools/toml-to-json/run",
        "schema_url": "/api/v1/tools/toml-to-json",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/toml-to-json/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/toml-to-json/"
    },
    {
      "id": "transpose-csv",
      "category": "data-tools",
      "built": true,
      "requirements": "Rows-to-columns with header options and empty-cell handling.",
      "implementation": {
        "fields": [
          {
            "key": "delimiter",
            "label": "CSV separator",
            "value": ",",
            "type": "select",
            "values": [
              ",",
              ";",
              "\t"
            ]
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/transpose-csv/run",
      "api": {
        "id": "transpose-csv",
        "name": "Transpose CSV",
        "category": "data-tools",
        "description": "Rows-to-columns with header options and empty-cell handling.",
        "notes": "",
        "human_path": "/en/data-tools/transpose-csv/",
        "method": "POST",
        "endpoint": "/api/v1/tools/transpose-csv/run",
        "schema_url": "/api/v1/tools/transpose-csv",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "delimiter": {
                  "type": "string",
                  "description": "CSV separator",
                  "default": ",",
                  "enum": [
                    ",",
                    ";",
                    "\t"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/transpose-csv/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/transpose-csv/"
    },
    {
      "id": "tsv-to-csv",
      "category": "data-tools",
      "built": true,
      "requirements": "Correctly quote embedded tabs, commas and newlines; preserve empty cells.",
      "implementation": {
        "fields": [
          {
            "key": "delimiter",
            "label": "CSV separator",
            "value": ",",
            "type": "select",
            "values": [
              ",",
              ";",
              "\t"
            ]
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "TSV",
          "placeholder": "name\tscore\nAda\t98",
          "help": "Separate columns with tabs and rows with new lines. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/tsv-to-csv/run",
      "api": {
        "id": "tsv-to-csv",
        "name": "TSV to CSV",
        "category": "data-tools",
        "description": "Convert TSV to CSV.",
        "notes": "",
        "human_path": "/en/data-tools/tsv-to-csv/",
        "method": "POST",
        "endpoint": "/api/v1/tools/tsv-to-csv/run",
        "schema_url": "/api/v1/tools/tsv-to-csv",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "delimiter": {
                  "type": "string",
                  "description": "CSV separator",
                  "default": ",",
                  "enum": [
                    ",",
                    ";",
                    "\t"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/tsv-to-csv/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/tsv-to-csv/"
    },
    {
      "id": "xml-to-csv",
      "category": "data-tools",
      "built": true,
      "requirements": "Select repeating record path; define attributes and nested-node flattening.",
      "implementation": {
        "fields": [
          {
            "key": "delimiter",
            "label": "CSV separator",
            "value": ",",
            "type": "select",
            "values": [
              ",",
              ";",
              "\t"
            ]
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "XML",
          "placeholder": "<item><name>Ada</name></item>",
          "help": "Include one root element and matching closing tags. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/xml-to-csv/run",
      "api": {
        "id": "xml-to-csv",
        "name": "XML to CSV",
        "category": "data-tools",
        "description": "Convert XML to CSV.",
        "notes": "",
        "human_path": "/en/data-tools/xml-to-csv/",
        "method": "POST",
        "endpoint": "/api/v1/tools/xml-to-csv/run",
        "schema_url": "/api/v1/tools/xml-to-csv",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "delimiter": {
                  "type": "string",
                  "description": "CSV separator",
                  "default": ",",
                  "enum": [
                    ",",
                    ";",
                    "\t"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/xml-to-csv/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/xml-to-csv/"
    },
    {
      "id": "xml-to-json",
      "category": "data-tools",
      "built": true,
      "requirements": "Define attribute/namespace/array mapping; disable external-entity resolution.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "XML",
          "placeholder": "<item><name>Ada</name></item>",
          "help": "Include one root element and matching closing tags. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/xml-to-json/run",
      "api": {
        "id": "xml-to-json",
        "name": "XML to JSON",
        "category": "data-tools",
        "description": "Convert XML to JSON.",
        "notes": "",
        "human_path": "/en/data-tools/xml-to-json/",
        "method": "POST",
        "endpoint": "/api/v1/tools/xml-to-json/run",
        "schema_url": "/api/v1/tools/xml-to-json",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/xml-to-json/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/xml-to-json/"
    },
    {
      "id": "yaml-to-csv",
      "category": "data-tools",
      "built": true,
      "requirements": "Support list-of-records input and explain nested structures.",
      "implementation": {
        "fields": [
          {
            "key": "delimiter",
            "label": "CSV separator",
            "value": ",",
            "type": "select",
            "values": [
              ",",
              ";",
              "\t"
            ]
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "YAML",
          "placeholder": "name: Ada\ncount: 2",
          "help": "Use spaces for indentation. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/yaml-to-csv/run",
      "api": {
        "id": "yaml-to-csv",
        "name": "YAML to CSV",
        "category": "data-tools",
        "description": "Convert YAML to CSV.",
        "notes": "",
        "human_path": "/en/data-tools/yaml-to-csv/",
        "method": "POST",
        "endpoint": "/api/v1/tools/yaml-to-csv/run",
        "schema_url": "/api/v1/tools/yaml-to-csv",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "delimiter": {
                  "type": "string",
                  "description": "CSV separator",
                  "default": ",",
                  "enum": [
                    ",",
                    ";",
                    "\t"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/yaml-to-csv/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/yaml-to-csv/"
    },
    {
      "id": "yaml-to-json",
      "category": "data-tools",
      "built": true,
      "requirements": "Safe parsing, alias limits and supported YAML schema; report unsupported tags.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "YAML",
          "placeholder": "name: Ada\ncount: 2",
          "help": "Use spaces for indentation. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/yaml-to-json/run",
      "api": {
        "id": "yaml-to-json",
        "name": "YAML to JSON",
        "category": "data-tools",
        "description": "Convert YAML to JSON.",
        "notes": "",
        "human_path": "/en/data-tools/yaml-to-json/",
        "method": "POST",
        "endpoint": "/api/v1/tools/yaml-to-json/run",
        "schema_url": "/api/v1/tools/yaml-to-json",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/data-tools/yaml-to-json/",
      "agent_url": "https://happytails.ai/agents/en/data-tools/yaml-to-json/"
    },
    {
      "id": "add-days",
      "category": "date-time-tools",
      "built": true,
      "requirements": "Add/subtract calendar days and expose timezone/calendar assumptions.",
      "implementation": {
        "fields": [
          {
            "key": "date",
            "label": "Date",
            "value": "2026-01-01",
            "type": "date"
          },
          {
            "key": "days",
            "label": "Days to add (negative subtracts)",
            "value": 30,
            "type": "number"
          }
        ],
        "input": false,
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/add-days/run",
      "api": {
        "id": "add-days",
        "name": "Add days",
        "category": "date-time-tools",
        "description": "Add/subtract calendar days and expose timezone/calendar assumptions.",
        "notes": "",
        "human_path": "/en/date-time-tools/add-days/",
        "method": "POST",
        "endpoint": "/api/v1/tools/add-days/run",
        "schema_url": "/api/v1/tools/add-days",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "date": {
                  "type": "string",
                  "description": "Date",
                  "default": "2026-01-01"
                },
                "days": {
                  "type": "number",
                  "description": "Days to add (negative subtracts)",
                  "default": 30.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/date-time-tools/add-days/",
      "agent_url": "https://happytails.ai/agents/en/date-time-tools/add-days/"
    },
    {
      "id": "age-calculator",
      "category": "date-time-tools",
      "built": true,
      "requirements": "Calendar age and next birthday; leap-day handling; dates stay local.",
      "implementation": {
        "fields": [
          {
            "key": "start",
            "label": "Start date",
            "value": "2026-01-01",
            "type": "date"
          },
          {
            "key": "end",
            "label": "End date",
            "value": "2026-12-31",
            "type": "date"
          },
          {
            "key": "holidays",
            "label": "Holidays to exclude (YYYY-MM-DD, comma separated)",
            "value": "",
            "type": "text"
          }
        ],
        "input": false,
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/age-calculator/run",
      "api": {
        "id": "age-calculator",
        "name": "Age calculator",
        "category": "date-time-tools",
        "description": "Calendar age and next birthday.",
        "notes": "",
        "human_path": "/en/date-time-tools/age-calculator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/age-calculator/run",
        "schema_url": "/api/v1/tools/age-calculator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "start": {
                  "type": "string",
                  "description": "Start date",
                  "default": "2026-01-01"
                },
                "end": {
                  "type": "string",
                  "description": "End date",
                  "default": "2026-12-31"
                },
                "holidays": {
                  "type": "string",
                  "description": "Holidays to exclude (YYYY-MM-DD, comma separated)",
                  "default": ""
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/date-time-tools/age-calculator/",
      "agent_url": "https://happytails.ai/agents/en/date-time-tools/age-calculator/"
    },
    {
      "id": "business-days",
      "category": "date-time-tools",
      "built": true,
      "requirements": "Custom weekends first; holiday calendars only when sourced/versioned by jurisdiction.",
      "implementation": {
        "fields": [
          {
            "key": "start",
            "label": "Start date",
            "value": "2026-01-01",
            "type": "date"
          },
          {
            "key": "end",
            "label": "End date",
            "value": "2026-12-31",
            "type": "date"
          },
          {
            "key": "holidays",
            "label": "Holidays to exclude (YYYY-MM-DD, comma separated)",
            "value": "",
            "type": "text"
          }
        ],
        "input": false,
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/business-days/run",
      "api": {
        "id": "business-days",
        "name": "Business days",
        "category": "date-time-tools",
        "description": "Custom weekends first.",
        "notes": "",
        "human_path": "/en/date-time-tools/business-days/",
        "method": "POST",
        "endpoint": "/api/v1/tools/business-days/run",
        "schema_url": "/api/v1/tools/business-days",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "start": {
                  "type": "string",
                  "description": "Start date",
                  "default": "2026-01-01"
                },
                "end": {
                  "type": "string",
                  "description": "End date",
                  "default": "2026-12-31"
                },
                "holidays": {
                  "type": "string",
                  "description": "Holidays to exclude (YYYY-MM-DD, comma separated)",
                  "default": ""
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/date-time-tools/business-days/",
      "agent_url": "https://happytails.ai/agents/en/date-time-tools/business-days/"
    },
    {
      "id": "date-difference",
      "category": "date-time-tools",
      "built": true,
      "requirements": "Inclusive/exclusive counting, leap years, calendar dates versus elapsed time.",
      "implementation": {
        "fields": [
          {
            "key": "start",
            "label": "Start date",
            "value": "2026-01-01",
            "type": "date"
          },
          {
            "key": "end",
            "label": "End date",
            "value": "2026-12-31",
            "type": "date"
          },
          {
            "key": "holidays",
            "label": "Holidays to exclude (YYYY-MM-DD, comma separated)",
            "value": "",
            "type": "text"
          }
        ],
        "input": false,
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/date-difference/run",
      "api": {
        "id": "date-difference",
        "name": "Date difference",
        "category": "date-time-tools",
        "description": "Inclusive/exclusive counting, leap years, calendar dates versus elapsed time.",
        "notes": "",
        "human_path": "/en/date-time-tools/date-difference/",
        "method": "POST",
        "endpoint": "/api/v1/tools/date-difference/run",
        "schema_url": "/api/v1/tools/date-difference",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "start": {
                  "type": "string",
                  "description": "Start date",
                  "default": "2026-01-01"
                },
                "end": {
                  "type": "string",
                  "description": "End date",
                  "default": "2026-12-31"
                },
                "holidays": {
                  "type": "string",
                  "description": "Holidays to exclude (YYYY-MM-DD, comma separated)",
                  "default": ""
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/date-time-tools/date-difference/",
      "agent_url": "https://happytails.ai/agents/en/date-time-tools/date-difference/"
    },
    {
      "id": "stopwatch",
      "category": "date-time-tools",
      "built": true,
      "requirements": "Lap times, keyboard controls and monotonic elapsed time.",
      "implementation": {
        "fields": [],
        "input": false,
        "note": "Elapsed time uses the browser’s monotonic clock.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": true
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": false,
        "name": null,
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/date-time-tools/stopwatch/",
      "agent_url": "https://happytails.ai/agents/en/date-time-tools/stopwatch/"
    },
    {
      "id": "time-calculator",
      "category": "date-time-tools",
      "built": true,
      "requirements": "Add/subtract hours/minutes/seconds and convert decimal hours.",
      "implementation": {
        "fields": [
          {
            "key": "start",
            "label": "Start time",
            "value": "09:00",
            "type": "text"
          },
          {
            "key": "end",
            "label": "End time",
            "value": "17:00",
            "type": "text"
          },
          {
            "key": "break",
            "label": "Unpaid break (minutes)",
            "value": 30,
            "type": "number"
          },
          {
            "key": "overnight",
            "label": "Ends next day",
            "value": false,
            "type": "checkbox"
          },
          {
            "key": "rate",
            "label": "Hourly rate",
            "value": 20,
            "type": "number"
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/time-calculator/run",
      "api": {
        "id": "time-calculator",
        "name": "Time calculator",
        "category": "date-time-tools",
        "description": "Add/subtract hours/minutes/seconds and convert decimal hours.",
        "notes": "",
        "human_path": "/en/date-time-tools/time-calculator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/time-calculator/run",
        "schema_url": "/api/v1/tools/time-calculator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "start": {
                  "type": "string",
                  "description": "Start time",
                  "default": "09:00"
                },
                "end": {
                  "type": "string",
                  "description": "End time",
                  "default": "17:00"
                },
                "break": {
                  "type": "number",
                  "description": "Unpaid break (minutes)",
                  "default": 30.0
                },
                "overnight": {
                  "type": "boolean",
                  "description": "Ends next day",
                  "default": false
                },
                "rate": {
                  "type": "number",
                  "description": "Hourly rate",
                  "default": 20.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/date-time-tools/time-calculator/",
      "agent_url": "https://happytails.ai/agents/en/date-time-tools/time-calculator/"
    },
    {
      "id": "time-card-calculator",
      "category": "date-time-tools",
      "built": true,
      "requirements": "Daily intervals, breaks and totals; do not imply compliance with payroll law.",
      "implementation": {
        "fields": [
          {
            "key": "start",
            "label": "Start time",
            "value": "09:00",
            "type": "text"
          },
          {
            "key": "end",
            "label": "End time",
            "value": "17:00",
            "type": "text"
          },
          {
            "key": "break",
            "label": "Unpaid break (minutes)",
            "value": 30,
            "type": "number"
          },
          {
            "key": "overnight",
            "label": "Ends next day",
            "value": false,
            "type": "checkbox"
          },
          {
            "key": "rate",
            "label": "Hourly rate",
            "value": 20,
            "type": "number"
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/time-card-calculator/run",
      "api": {
        "id": "time-card-calculator",
        "name": "Time card calculator",
        "category": "date-time-tools",
        "description": "Daily intervals, breaks and totals.",
        "notes": "",
        "human_path": "/en/date-time-tools/time-card-calculator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/time-card-calculator/run",
        "schema_url": "/api/v1/tools/time-card-calculator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "start": {
                  "type": "string",
                  "description": "Start time",
                  "default": "09:00"
                },
                "end": {
                  "type": "string",
                  "description": "End time",
                  "default": "17:00"
                },
                "break": {
                  "type": "number",
                  "description": "Unpaid break (minutes)",
                  "default": 30.0
                },
                "overnight": {
                  "type": "boolean",
                  "description": "Ends next day",
                  "default": false
                },
                "rate": {
                  "type": "number",
                  "description": "Hourly rate",
                  "default": 20.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/date-time-tools/time-card-calculator/",
      "agent_url": "https://happytails.ai/agents/en/date-time-tools/time-card-calculator/"
    },
    {
      "id": "time-duration",
      "category": "date-time-tools",
      "built": true,
      "requirements": "Start/end times, crossing midnight, breaks, decimal hours and explicit timezone handling.",
      "implementation": {
        "fields": [
          {
            "key": "start",
            "label": "Start time",
            "value": "09:00",
            "type": "text"
          },
          {
            "key": "end",
            "label": "End time",
            "value": "17:00",
            "type": "text"
          },
          {
            "key": "break",
            "label": "Unpaid break (minutes)",
            "value": 30,
            "type": "number"
          },
          {
            "key": "overnight",
            "label": "Ends next day",
            "value": false,
            "type": "checkbox"
          },
          {
            "key": "rate",
            "label": "Hourly rate",
            "value": 20,
            "type": "number"
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/time-duration/run",
      "api": {
        "id": "time-duration",
        "name": "Time duration",
        "category": "date-time-tools",
        "description": "Start/end times, crossing midnight, breaks, decimal hours and explicit timezone handling.",
        "notes": "",
        "human_path": "/en/date-time-tools/time-duration/",
        "method": "POST",
        "endpoint": "/api/v1/tools/time-duration/run",
        "schema_url": "/api/v1/tools/time-duration",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "start": {
                  "type": "string",
                  "description": "Start time",
                  "default": "09:00"
                },
                "end": {
                  "type": "string",
                  "description": "End time",
                  "default": "17:00"
                },
                "break": {
                  "type": "number",
                  "description": "Unpaid break (minutes)",
                  "default": 30.0
                },
                "overnight": {
                  "type": "boolean",
                  "description": "Ends next day",
                  "default": false
                },
                "rate": {
                  "type": "number",
                  "description": "Hourly rate",
                  "default": 20.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/date-time-tools/time-duration/",
      "agent_url": "https://happytails.ai/agents/en/date-time-tools/time-duration/"
    },
    {
      "id": "time-zone-converter",
      "category": "date-time-tools",
      "built": true,
      "requirements": "IANA zones, date selection and DST ambiguity; compare working hours.",
      "implementation": {
        "fields": [
          {
            "key": "zone",
            "label": "Destination IANA timezone",
            "value": "America/New_York",
            "type": "text"
          }
        ],
        "note": "Use an explicit source offset to avoid ambiguous daylight-saving times.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/time-zone-converter/run",
      "api": {
        "id": "time-zone-converter",
        "name": "Time zone converter",
        "category": "date-time-tools",
        "description": "IANA zones, date selection and DST ambiguity.",
        "notes": "Use an explicit source offset to avoid ambiguous daylight-saving times.",
        "human_path": "/en/date-time-tools/time-zone-converter/",
        "method": "POST",
        "endpoint": "/api/v1/tools/time-zone-converter/run",
        "schema_url": "/api/v1/tools/time-zone-converter",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "zone": {
                  "type": "string",
                  "description": "Destination IANA timezone",
                  "default": "America/New_York"
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/date-time-tools/time-zone-converter/",
      "agent_url": "https://happytails.ai/agents/en/date-time-tools/time-zone-converter/"
    },
    {
      "id": "timer",
      "category": "date-time-tools",
      "built": true,
      "requirements": "Keyboard controls and elapsed-time correction; explain background-tab alarm limits.",
      "implementation": {
        "fields": [],
        "input": false,
        "note": "Keep the page open. Background tabs and sleeping devices can delay completion notifications.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": true
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": false,
        "name": null,
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/date-time-tools/timer/",
      "agent_url": "https://happytails.ai/agents/en/date-time-tools/timer/"
    },
    {
      "id": "aspect-ratio-calculator",
      "category": "design-tools",
      "built": true,
      "requirements": "Calculate ratio or missing dimension; rounding and crop-versus-fit explanation.",
      "implementation": {
        "fields": [
          {
            "key": "w",
            "label": "Width",
            "value": 1920,
            "type": "number"
          },
          {
            "key": "h",
            "label": "Height",
            "value": 1080,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/aspect-ratio-calculator/run",
      "api": {
        "id": "aspect-ratio-calculator",
        "name": "Aspect ratio calculator",
        "category": "design-tools",
        "description": "Find the simplest aspect ratio from a width and height.",
        "notes": "",
        "human_path": "/en/design-tools/aspect-ratio-calculator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/aspect-ratio-calculator/run",
        "schema_url": "/api/v1/tools/aspect-ratio-calculator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "w": {
                  "type": "number",
                  "description": "Width",
                  "default": 1920.0
                },
                "h": {
                  "type": "number",
                  "description": "Height",
                  "default": 1080.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/design-tools/aspect-ratio-calculator/",
      "agent_url": "https://happytails.ai/agents/en/design-tools/aspect-ratio-calculator/"
    },
    {
      "id": "collage-maker",
      "category": "design-tools",
      "built": true,
      "requirements": "Grid layouts, spacing, aspect ratios and output-size controls.",
      "implementation": {
        "fields": [
          {
            "key": "direction",
            "label": "Arrange",
            "value": "Horizontal",
            "type": "select",
            "values": [
              "Horizontal",
              "Vertical"
            ]
          },
          {
            "key": "background",
            "label": "Background",
            "value": "#ffffff",
            "type": "color"
          }
        ],
        "files": true,
        "multiple": true,
        "input": false,
        "accept": "image/*,.svg,.avif",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/design-tools/collage-maker/",
      "agent_url": "https://happytails.ai/agents/en/design-tools/collage-maker/"
    },
    {
      "id": "color-palette-from-image",
      "category": "design-tools",
      "built": true,
      "requirements": "Extract representative colors with controllable palette size; preserve no-upload claim only if true.",
      "implementation": {
        "fields": [
          {
            "key": "n",
            "label": "Palette colors",
            "value": 6,
            "type": "number"
          }
        ],
        "files": true,
        "input": false,
        "note": "Dominant colors from a quantized 100×100 sample; small image details may be omitted.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/design-tools/color-palette-from-image/",
      "agent_url": "https://happytails.ai/agents/en/design-tools/color-palette-from-image/"
    },
    {
      "id": "color-picker",
      "category": "design-tools",
      "built": true,
      "requirements": "Image upload sampling plus manual color entry; clarify color-space and eyedropper support.",
      "implementation": {
        "fields": [
          {
            "key": "color",
            "label": "Color",
            "value": "#3366cc",
            "type": "color"
          }
        ],
        "experience": {
          "automatic": true,
          "single": true,
          "label": "Color value",
          "placeholder": "#3366cc",
          "help": "Enter a hex color or use the color picker. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/color-picker/run",
      "api": {
        "id": "color-picker",
        "name": "Color picker",
        "category": "design-tools",
        "description": "Image upload sampling plus manual color entry.",
        "notes": "",
        "human_path": "/en/design-tools/color-picker/",
        "method": "POST",
        "endpoint": "/api/v1/tools/color-picker/run",
        "schema_url": "/api/v1/tools/color-picker",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "color": {
                  "type": "string",
                  "description": "Color",
                  "default": "#3366cc"
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/design-tools/color-picker/",
      "agent_url": "https://happytails.ai/agents/en/design-tools/color-picker/"
    },
    {
      "id": "color-shades",
      "category": "design-tools",
      "built": true,
      "requirements": "Generate tints/shades with defined color-space interpolation and HEX/CSS output.",
      "implementation": {
        "fields": [
          {
            "key": "color",
            "label": "Base color",
            "value": "#3366cc",
            "type": "color"
          },
          {
            "key": "n",
            "label": "Shades",
            "value": 9,
            "type": "number"
          }
        ],
        "input": false,
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/color-shades/run",
      "api": {
        "id": "color-shades",
        "name": "Color shades",
        "category": "design-tools",
        "description": "Generate tints/shades with defined color-space interpolation and HEX/CSS output.",
        "notes": "",
        "human_path": "/en/design-tools/color-shades/",
        "method": "POST",
        "endpoint": "/api/v1/tools/color-shades/run",
        "schema_url": "/api/v1/tools/color-shades",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "color": {
                  "type": "string",
                  "description": "Base color",
                  "default": "#3366cc"
                },
                "n": {
                  "type": "number",
                  "description": "Shades",
                  "default": 9.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/design-tools/color-shades/",
      "agent_url": "https://happytails.ai/agents/en/design-tools/color-shades/"
    },
    {
      "id": "contrast-checker",
      "category": "design-tools",
      "built": true,
      "requirements": "Compute stated WCAG ratio for foreground/background; AA/AAA labels with text-size context.",
      "implementation": {
        "fields": [
          {
            "key": "foreground",
            "label": "Text",
            "value": "#222222",
            "type": "color"
          },
          {
            "key": "background",
            "label": "Background",
            "value": "#ffffff",
            "type": "color"
          }
        ],
        "input": false,
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/contrast-checker/run",
      "api": {
        "id": "contrast-checker",
        "name": "Contrast checker",
        "category": "design-tools",
        "description": "Compute stated WCAG ratio for foreground/background.",
        "notes": "",
        "human_path": "/en/design-tools/contrast-checker/",
        "method": "POST",
        "endpoint": "/api/v1/tools/contrast-checker/run",
        "schema_url": "/api/v1/tools/contrast-checker",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "foreground": {
                  "type": "string",
                  "description": "Text",
                  "default": "#222222"
                },
                "background": {
                  "type": "string",
                  "description": "Background",
                  "default": "#ffffff"
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/design-tools/contrast-checker/",
      "agent_url": "https://happytails.ai/agents/en/design-tools/contrast-checker/"
    },
    {
      "id": "css-box-shadow",
      "category": "design-tools",
      "built": true,
      "requirements": "Visual controls and accessible code output; multiple shadow layers.",
      "implementation": {
        "fields": [
          {
            "key": "x",
            "label": "Horizontal",
            "value": 0,
            "type": "number"
          },
          {
            "key": "y",
            "label": "Vertical",
            "value": 4,
            "type": "number"
          },
          {
            "key": "blur",
            "label": "Blur",
            "value": 12,
            "type": "number"
          },
          {
            "key": "spread",
            "label": "Spread",
            "value": 0,
            "type": "number"
          },
          {
            "key": "color",
            "label": "Color",
            "value": "#333333",
            "type": "color"
          }
        ],
        "input": false,
        "experience": {
          "automatic": true,
          "single": false,
          "label": "CSS",
          "placeholder": "a { color: #3366cc; }",
          "help": "Paste CSS rules, including their selectors. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/css-box-shadow/run",
      "api": {
        "id": "css-box-shadow",
        "name": "CSS box shadow",
        "category": "design-tools",
        "description": "Visual controls and accessible code output.",
        "notes": "",
        "human_path": "/en/design-tools/css-box-shadow/",
        "method": "POST",
        "endpoint": "/api/v1/tools/css-box-shadow/run",
        "schema_url": "/api/v1/tools/css-box-shadow",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "x": {
                  "type": "number",
                  "description": "Horizontal",
                  "default": 0.0
                },
                "y": {
                  "type": "number",
                  "description": "Vertical",
                  "default": 4.0
                },
                "blur": {
                  "type": "number",
                  "description": "Blur",
                  "default": 12.0
                },
                "spread": {
                  "type": "number",
                  "description": "Spread",
                  "default": 0.0
                },
                "color": {
                  "type": "string",
                  "description": "Color",
                  "default": "#333333"
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/design-tools/css-box-shadow/",
      "agent_url": "https://happytails.ai/agents/en/design-tools/css-box-shadow/"
    },
    {
      "id": "css-flexbox",
      "category": "design-tools",
      "built": true,
      "requirements": "Responsive interactive preview with generated CSS and minimal HTML.",
      "implementation": {
        "fields": [
          {
            "key": "direction",
            "label": "Direction",
            "value": "row",
            "type": "select",
            "values": [
              "row",
              "column",
              "row-reverse",
              "column-reverse"
            ]
          },
          {
            "key": "justify",
            "label": "Justify",
            "value": "flex-start",
            "type": "select",
            "values": [
              "flex-start",
              "center",
              "space-between",
              "space-around",
              "flex-end"
            ]
          },
          {
            "key": "align",
            "label": "Align",
            "value": "stretch",
            "type": "select",
            "values": [
              "stretch",
              "center",
              "flex-start",
              "flex-end"
            ]
          },
          {
            "key": "wrap",
            "label": "Wrap",
            "value": "wrap",
            "type": "select",
            "values": [
              "wrap",
              "nowrap"
            ]
          },
          {
            "key": "gap",
            "label": "Gap (px)",
            "value": 16,
            "type": "number"
          }
        ],
        "input": false,
        "experience": {
          "automatic": true,
          "single": false,
          "label": "CSS",
          "placeholder": "a { color: #3366cc; }",
          "help": "Paste CSS rules, including their selectors. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/css-flexbox/run",
      "api": {
        "id": "css-flexbox",
        "name": "CSS flexbox",
        "category": "design-tools",
        "description": "Responsive interactive preview with generated CSS and minimal HTML.",
        "notes": "",
        "human_path": "/en/design-tools/css-flexbox/",
        "method": "POST",
        "endpoint": "/api/v1/tools/css-flexbox/run",
        "schema_url": "/api/v1/tools/css-flexbox",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "direction": {
                  "type": "string",
                  "description": "Direction",
                  "default": "row",
                  "enum": [
                    "row",
                    "column",
                    "row-reverse",
                    "column-reverse"
                  ]
                },
                "justify": {
                  "type": "string",
                  "description": "Justify",
                  "default": "flex-start",
                  "enum": [
                    "flex-start",
                    "center",
                    "space-between",
                    "space-around",
                    "flex-end"
                  ]
                },
                "align": {
                  "type": "string",
                  "description": "Align",
                  "default": "stretch",
                  "enum": [
                    "stretch",
                    "center",
                    "flex-start",
                    "flex-end"
                  ]
                },
                "wrap": {
                  "type": "string",
                  "description": "Wrap",
                  "default": "wrap",
                  "enum": [
                    "wrap",
                    "nowrap"
                  ]
                },
                "gap": {
                  "type": "number",
                  "description": "Gap (px)",
                  "default": 16.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/design-tools/css-flexbox/",
      "agent_url": "https://happytails.ai/agents/en/design-tools/css-flexbox/"
    },
    {
      "id": "css-grid",
      "category": "design-tools",
      "built": true,
      "requirements": "Rows, columns, gaps and placements; responsive code output.",
      "implementation": {
        "fields": [
          {
            "key": "columns",
            "label": "Columns",
            "value": 3,
            "type": "number"
          },
          {
            "key": "gap",
            "label": "Gap (px)",
            "value": 16,
            "type": "number"
          }
        ],
        "input": false,
        "experience": {
          "automatic": true,
          "single": false,
          "label": "CSS",
          "placeholder": "a { color: #3366cc; }",
          "help": "Paste CSS rules, including their selectors. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/css-grid/run",
      "api": {
        "id": "css-grid",
        "name": "CSS grid",
        "category": "design-tools",
        "description": "Rows, columns, gaps and placements.",
        "notes": "",
        "human_path": "/en/design-tools/css-grid/",
        "method": "POST",
        "endpoint": "/api/v1/tools/css-grid/run",
        "schema_url": "/api/v1/tools/css-grid",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "columns": {
                  "type": "number",
                  "description": "Columns",
                  "default": 3.0
                },
                "gap": {
                  "type": "number",
                  "description": "Gap (px)",
                  "default": 16.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/design-tools/css-grid/",
      "agent_url": "https://happytails.ai/agents/en/design-tools/css-grid/"
    },
    {
      "id": "curved-text-generator",
      "category": "design-tools",
      "built": true,
      "requirements": "Place text on adjustable arcs or circles with radius, direction and spacing controls; preview and export PNG or SVG with reliable font handling; use shape presets within one tool rather than duplicating pages for every curve.",
      "implementation": {
        "fields": [
          {
            "key": "size",
            "label": "Font size",
            "value": 48,
            "type": "number"
          },
          {
            "key": "width",
            "label": "Canvas width",
            "value": 800,
            "type": "number"
          },
          {
            "key": "height",
            "label": "Canvas height",
            "value": 300,
            "type": "number"
          },
          {
            "key": "color",
            "label": "Text",
            "value": "#171717",
            "type": "color"
          },
          {
            "key": "background",
            "label": "Background",
            "value": "#ffffff",
            "type": "color"
          },
          {
            "key": "curve",
            "label": "Curve height",
            "value": 200,
            "type": "number"
          }
        ],
        "note": "SVG export uses your system sans-serif font. Check wrapping and font appearance in the destination.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/curved-text-generator/run",
      "api": {
        "id": "curved-text-generator",
        "name": "Curved text generator",
        "category": "design-tools",
        "description": "Place text on adjustable arcs or circles with radius, direction and spacing controls.",
        "notes": "SVG export uses your system sans-serif font. Check wrapping and font appearance in the destination.",
        "human_path": "/en/design-tools/curved-text-generator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/curved-text-generator/run",
        "schema_url": "/api/v1/tools/curved-text-generator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "size": {
                  "type": "number",
                  "description": "Font size",
                  "default": 48.0
                },
                "width": {
                  "type": "number",
                  "description": "Canvas width",
                  "default": 800.0
                },
                "height": {
                  "type": "number",
                  "description": "Canvas height",
                  "default": 300.0
                },
                "color": {
                  "type": "string",
                  "description": "Text",
                  "default": "#171717"
                },
                "background": {
                  "type": "string",
                  "description": "Background",
                  "default": "#ffffff"
                },
                "curve": {
                  "type": "number",
                  "description": "Curve height",
                  "default": 200.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/design-tools/curved-text-generator/",
      "agent_url": "https://happytails.ai/agents/en/design-tools/curved-text-generator/"
    },
    {
      "id": "favicon-generator",
      "category": "design-tools",
      "built": true,
      "requirements": "Preview small-size legibility; export real ICO/PNG sizes and useful HTML snippet.",
      "implementation": {
        "fields": [
          {
            "key": "size",
            "label": "Icon size",
            "value": "32",
            "type": "select",
            "values": [
              "16",
              "32",
              "48",
              "64",
              "128",
              "256"
            ]
          }
        ],
        "files": true,
        "input": false,
        "accept": "image/*,.svg,.avif",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/design-tools/favicon-generator/",
      "agent_url": "https://happytails.ai/agents/en/design-tools/favicon-generator/"
    },
    {
      "id": "gradient-generator",
      "category": "design-tools",
      "built": true,
      "requirements": "Linear/radial stops, angle and CSS export; contrast preview as optional help.",
      "implementation": {
        "fields": [
          {
            "key": "a",
            "label": "Start",
            "value": "#3366cc",
            "type": "color"
          },
          {
            "key": "b",
            "label": "End",
            "value": "#ff5599",
            "type": "color"
          },
          {
            "key": "angle",
            "label": "Angle",
            "value": 90,
            "type": "number"
          }
        ],
        "input": false,
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/gradient-generator/run",
      "api": {
        "id": "gradient-generator",
        "name": "Gradient generator",
        "category": "design-tools",
        "description": "Linear/radial stops, angle and CSS export.",
        "notes": "",
        "human_path": "/en/design-tools/gradient-generator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/gradient-generator/run",
        "schema_url": "/api/v1/tools/gradient-generator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "a": {
                  "type": "string",
                  "description": "Start",
                  "default": "#3366cc"
                },
                "b": {
                  "type": "string",
                  "description": "End",
                  "default": "#ff5599"
                },
                "angle": {
                  "type": "number",
                  "description": "Angle",
                  "default": 90.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/design-tools/gradient-generator/",
      "agent_url": "https://happytails.ai/agents/en/design-tools/gradient-generator/"
    },
    {
      "id": "hex-to-rgb",
      "category": "design-tools",
      "built": true,
      "requirements": "3/6/8-digit HEX support and explicit alpha interpretation; copy CSS output.",
      "implementation": {
        "fields": [
          {
            "key": "color",
            "label": "Color",
            "value": "#3366cc",
            "type": "color"
          }
        ],
        "experience": {
          "automatic": true,
          "single": true,
          "label": "Hex color",
          "placeholder": "#3366cc",
          "help": "Enter a hex color or use the color picker. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/hex-to-rgb/run",
      "api": {
        "id": "hex-to-rgb",
        "name": "Hex to RGB",
        "category": "design-tools",
        "description": "3/6/8-digit HEX support and explicit alpha interpretation.",
        "notes": "",
        "human_path": "/en/design-tools/hex-to-rgb/",
        "method": "POST",
        "endpoint": "/api/v1/tools/hex-to-rgb/run",
        "schema_url": "/api/v1/tools/hex-to-rgb",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "color": {
                  "type": "string",
                  "description": "Color",
                  "default": "#3366cc"
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/design-tools/hex-to-rgb/",
      "agent_url": "https://happytails.ai/agents/en/design-tools/hex-to-rgb/"
    },
    {
      "id": "palette-generator",
      "category": "design-tools",
      "built": true,
      "requirements": "Generate from image or seed; lock colors and export HEX/CSS; label accessibility checks separately.",
      "implementation": {
        "fields": [
          {
            "key": "color",
            "label": "Base color",
            "value": "#3366cc",
            "type": "color"
          },
          {
            "key": "n",
            "label": "Shades",
            "value": 9,
            "type": "number"
          }
        ],
        "input": false,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/palette-generator/run",
      "api": {
        "id": "palette-generator",
        "name": "Palette generator",
        "category": "design-tools",
        "description": "Generate from image or seed.",
        "notes": "",
        "human_path": "/en/design-tools/palette-generator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/palette-generator/run",
        "schema_url": "/api/v1/tools/palette-generator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "color": {
                  "type": "string",
                  "description": "Base color",
                  "default": "#3366cc"
                },
                "n": {
                  "type": "number",
                  "description": "Shades",
                  "default": 9.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/design-tools/palette-generator/",
      "agent_url": "https://happytails.ai/agents/en/design-tools/palette-generator/"
    },
    {
      "id": "palette-visualizer",
      "category": "design-tools",
      "built": true,
      "requirements": "Preview selected colors on realistic text/surface components without claiming complete accessibility.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/design-tools/palette-visualizer/",
      "agent_url": "https://happytails.ai/agents/en/design-tools/palette-visualizer/"
    },
    {
      "id": "rgb-to-hex",
      "category": "design-tools",
      "built": true,
      "requirements": "Validate channel ranges and alpha; define rounding of percentage inputs.",
      "implementation": {
        "fields": [
          {
            "key": "color",
            "label": "Color",
            "value": "#3366cc",
            "type": "color"
          }
        ],
        "experience": {
          "automatic": true,
          "single": true,
          "label": "RGB color",
          "placeholder": "51, 102, 204",
          "help": "Enter red, green and blue values from 0 to 255, separated by commas. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/rgb-to-hex/run",
      "api": {
        "id": "rgb-to-hex",
        "name": "RGB to hex",
        "category": "design-tools",
        "description": "Validate channel ranges and alpha.",
        "notes": "",
        "human_path": "/en/design-tools/rgb-to-hex/",
        "method": "POST",
        "endpoint": "/api/v1/tools/rgb-to-hex/run",
        "schema_url": "/api/v1/tools/rgb-to-hex",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "color": {
                  "type": "string",
                  "description": "Color",
                  "default": "#3366cc"
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/design-tools/rgb-to-hex/",
      "agent_url": "https://happytails.ai/agents/en/design-tools/rgb-to-hex/"
    },
    {
      "id": "svg-optimizer",
      "category": "design-tools",
      "built": true,
      "requirements": "Before/after render and size; preserve IDs/accessibility when requested; no active-content execution.",
      "implementation": {
        "fields": [],
        "note": "Optimizes SVG source. This is not an SVG sanitizer; inspect external links and scripts before embedding untrusted markup.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "SVG source",
          "placeholder": "<svg xmlns=\"http://www.w3.org/2000/svg\"><rect width=\"20\" height=\"20\"/></svg>",
          "help": "Paste complete SVG markup, including the outer svg element. Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/svg-optimizer/run",
      "api": {
        "id": "svg-optimizer",
        "name": "SVG optimizer",
        "category": "design-tools",
        "description": "Before/after render and size.",
        "notes": "Optimizes SVG source. This is not an SVG sanitizer; inspect external links and scripts before embedding untrusted markup.",
        "human_path": "/en/design-tools/svg-optimizer/",
        "method": "POST",
        "endpoint": "/api/v1/tools/svg-optimizer/run",
        "schema_url": "/api/v1/tools/svg-optimizer",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/design-tools/svg-optimizer/",
      "agent_url": "https://happytails.ai/agents/en/design-tools/svg-optimizer/"
    },
    {
      "id": "word-art-generator",
      "category": "design-tools",
      "built": true,
      "requirements": "Create styled or stacked display text with font, fill, outline, spacing and layout controls; preview PNG and SVG export with font licensing and portable rendering handled; keep word-cloud frequency visualization distinct.",
      "implementation": {
        "fields": [
          {
            "key": "size",
            "label": "Font size",
            "value": 48,
            "type": "number"
          },
          {
            "key": "width",
            "label": "Canvas width",
            "value": 800,
            "type": "number"
          },
          {
            "key": "height",
            "label": "Canvas height",
            "value": 300,
            "type": "number"
          },
          {
            "key": "color",
            "label": "Text",
            "value": "#171717",
            "type": "color"
          },
          {
            "key": "background",
            "label": "Background",
            "value": "#ffffff",
            "type": "color"
          },
          {
            "key": "outline",
            "label": "Outline",
            "value": "#171717",
            "type": "color"
          }
        ],
        "note": "SVG export uses your system sans-serif font. Check wrapping and font appearance in the destination.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/word-art-generator/run",
      "api": {
        "id": "word-art-generator",
        "name": "Word art generator",
        "category": "design-tools",
        "description": "Create styled or stacked display text with font, fill, outline, spacing and layout controls.",
        "notes": "SVG export uses your system sans-serif font. Check wrapping and font appearance in the destination.",
        "human_path": "/en/design-tools/word-art-generator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/word-art-generator/run",
        "schema_url": "/api/v1/tools/word-art-generator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "size": {
                  "type": "number",
                  "description": "Font size",
                  "default": 48.0
                },
                "width": {
                  "type": "number",
                  "description": "Canvas width",
                  "default": 800.0
                },
                "height": {
                  "type": "number",
                  "description": "Canvas height",
                  "default": 300.0
                },
                "color": {
                  "type": "string",
                  "description": "Text",
                  "default": "#171717"
                },
                "background": {
                  "type": "string",
                  "description": "Background",
                  "default": "#ffffff"
                },
                "outline": {
                  "type": "string",
                  "description": "Outline",
                  "default": "#171717"
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/design-tools/word-art-generator/",
      "agent_url": "https://happytails.ai/agents/en/design-tools/word-art-generator/"
    },
    {
      "id": "ascii-to-text",
      "category": "developer-tools",
      "built": true,
      "requirements": "Decimal/hex ASCII codes and explicit distinction from Unicode.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Decimal byte values",
          "placeholder": "72 105",
          "help": "Separate decimal byte values from 0 to 255 with spaces or commas. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/ascii-to-text/run",
      "api": {
        "id": "ascii-to-text",
        "name": "ASCII to text",
        "category": "developer-tools",
        "description": "Decimal/hex ASCII codes and explicit distinction from Unicode.",
        "notes": "",
        "human_path": "/en/developer-tools/ascii-to-text/",
        "method": "POST",
        "endpoint": "/api/v1/tools/ascii-to-text/run",
        "schema_url": "/api/v1/tools/ascii-to-text",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/ascii-to-text/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/ascii-to-text/"
    },
    {
      "id": "base64-encoder-decoder",
      "category": "developer-tools",
      "built": true,
      "requirements": "Encode/decode tabs; UTF-8 and binary handling; Base64URL option and invalid-input errors.",
      "implementation": {
        "fields": [
          {
            "key": "direction",
            "label": "Direction",
            "value": "Encode",
            "type": "select",
            "values": [
              "Encode",
              "Decode"
            ]
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/base64-encoder-decoder/run",
      "api": {
        "id": "base64-encoder-decoder",
        "name": "Base64 encoder decoder",
        "category": "developer-tools",
        "description": "Encode/decode tabs.",
        "notes": "",
        "human_path": "/en/developer-tools/base64-encoder-decoder/",
        "method": "POST",
        "endpoint": "/api/v1/tools/base64-encoder-decoder/run",
        "schema_url": "/api/v1/tools/base64-encoder-decoder",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "direction": {
                  "type": "string",
                  "description": "Direction",
                  "default": "Encode",
                  "enum": [
                    "Encode",
                    "Decode"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/base64-encoder-decoder/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/base64-encoder-decoder/"
    },
    {
      "id": "bcrypt-generator",
      "category": "developer-tools",
      "built": true,
      "requirements": "Generate and verify locally with work-factor control; cap compute time.",
      "implementation": {
        "fields": [
          {
            "key": "rounds",
            "label": "Cost factor",
            "value": 10,
            "type": "number"
          }
        ],
        "note": "A new random salt is generated for each hash. Input is limited to 72 UTF-8 bytes by bcrypt.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/bcrypt-generator/run",
      "api": {
        "id": "bcrypt-generator",
        "name": "Bcrypt generator",
        "category": "developer-tools",
        "description": "Generate and verify locally with work-factor control.",
        "notes": "A new random salt is generated for each hash. Input is limited to 72 UTF-8 bytes by bcrypt.",
        "human_path": "/en/developer-tools/bcrypt-generator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/bcrypt-generator/run",
        "schema_url": "/api/v1/tools/bcrypt-generator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "rounds": {
                  "type": "number",
                  "description": "Cost factor",
                  "default": 10.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/bcrypt-generator/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/bcrypt-generator/"
    },
    {
      "id": "binary-to-text",
      "category": "developer-tools",
      "built": true,
      "requirements": "Decode bytes using chosen text encoding; encode reverse direction in the same tool.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Binary bytes",
          "placeholder": "01001000 01101001",
          "help": "Separate 8-bit byte values with spaces or commas. Decoded bytes must form valid UTF-8. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/binary-to-text/run",
      "api": {
        "id": "binary-to-text",
        "name": "Binary to text",
        "category": "developer-tools",
        "description": "Decode binary byte values into UTF-8 text.",
        "notes": "",
        "human_path": "/en/developer-tools/binary-to-text/",
        "method": "POST",
        "endpoint": "/api/v1/tools/binary-to-text/run",
        "schema_url": "/api/v1/tools/binary-to-text",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/binary-to-text/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/binary-to-text/"
    },
    {
      "id": "chmod-calculator",
      "category": "developer-tools",
      "built": true,
      "requirements": "Numeric and symbolic Unix permission mapping; special bits and file-versus-directory meaning.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": true,
          "label": "Octal permissions",
          "placeholder": "755",
          "help": "Enter three octal digits, each from 0 to 7. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/chmod-calculator/run",
      "api": {
        "id": "chmod-calculator",
        "name": "Chmod calculator",
        "category": "developer-tools",
        "description": "Numeric and symbolic Unix permission mapping.",
        "notes": "",
        "human_path": "/en/developer-tools/chmod-calculator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/chmod-calculator/run",
        "schema_url": "/api/v1/tools/chmod-calculator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/chmod-calculator/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/chmod-calculator/"
    },
    {
      "id": "cron-parser",
      "category": "developer-tools",
      "built": true,
      "requirements": "Cron dialect and time-zone selection; show next runs and daylight-saving ambiguity.",
      "implementation": {
        "fields": [
          {
            "key": "zone",
            "label": "IANA time zone",
            "value": "UTC",
            "type": "text"
          },
          {
            "key": "start",
            "label": "Start ISO date (blank = now)",
            "value": "",
            "type": "text"
          },
          {
            "key": "n",
            "label": "Next occurrences",
            "value": 10,
            "type": "number"
          }
        ],
        "experience": {
          "automatic": false,
          "single": true,
          "label": "Cron expression",
          "placeholder": "0 9 * * 1",
          "help": "Enter a cron expression and choose the time zone below. Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/cron-parser/run",
      "api": {
        "id": "cron-parser",
        "name": "Cron parser",
        "category": "developer-tools",
        "description": "Cron dialect and time-zone selection.",
        "notes": "",
        "human_path": "/en/developer-tools/cron-parser/",
        "method": "POST",
        "endpoint": "/api/v1/tools/cron-parser/run",
        "schema_url": "/api/v1/tools/cron-parser",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "zone": {
                  "type": "string",
                  "description": "IANA time zone",
                  "default": "UTC"
                },
                "start": {
                  "type": "string",
                  "description": "Start ISO date (blank = now)",
                  "default": ""
                },
                "n": {
                  "type": "number",
                  "description": "Next occurrences",
                  "default": 10.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/cron-parser/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/cron-parser/"
    },
    {
      "id": "css-formatter",
      "category": "developer-tools",
      "built": true,
      "requirements": "Format/minify CSS with parser-based errors; retain semantics.",
      "implementation": {
        "fields": [],
        "note": "Formatting parses your source; it does not execute it.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "CSS",
          "placeholder": "a { color: #3366cc; }",
          "help": "Paste CSS rules, including their selectors. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/css-formatter/run",
      "api": {
        "id": "css-formatter",
        "name": "CSS formatter",
        "category": "developer-tools",
        "description": "Format/minify CSS with parser-based errors.",
        "notes": "Formatting parses your source; it does not execute it.",
        "human_path": "/en/developer-tools/css-formatter/",
        "method": "POST",
        "endpoint": "/api/v1/tools/css-formatter/run",
        "schema_url": "/api/v1/tools/css-formatter",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/css-formatter/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/css-formatter/"
    },
    {
      "id": "css-inliner",
      "category": "developer-tools",
      "built": true,
      "requirements": "Inline supported selectors for email HTML; preserve unsupported-rule warnings.",
      "implementation": {
        "fields": [
          {
            "key": "css",
            "label": "Additional CSS",
            "value": "",
            "type": "textarea"
          }
        ],
        "note": "Inlines supported rules locally. Media queries, pseudo-class behavior, external stylesheets and email-client rendering need review. External stylesheets are not fetched.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "CSS",
          "placeholder": "a { color: #3366cc; }",
          "help": "Paste CSS rules, including their selectors. Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/css-inliner/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/css-inliner/"
    },
    {
      "id": "css-minifier",
      "category": "developer-tools",
      "built": true,
      "requirements": "Pinned parser with source-size comparison and downloadable output.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": false,
          "single": false,
          "label": "CSS",
          "placeholder": "a { color: #3366cc; }",
          "help": "Paste CSS rules, including their selectors. Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/css-minifier/run",
      "api": {
        "id": "css-minifier",
        "name": "CSS minifier",
        "category": "developer-tools",
        "description": "Pinned parser with source-size comparison and downloadable output.",
        "notes": "",
        "human_path": "/en/developer-tools/css-minifier/",
        "method": "POST",
        "endpoint": "/api/v1/tools/css-minifier/run",
        "schema_url": "/api/v1/tools/css-minifier",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/css-minifier/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/css-minifier/"
    },
    {
      "id": "curl-to-code",
      "category": "developer-tools",
      "built": true,
      "requirements": "Parse quoting, headers and body; Python, JavaScript and PHP tabs; never execute requests.",
      "implementation": {
        "fields": [
          {
            "key": "language",
            "label": "Language",
            "value": "JavaScript",
            "type": "select",
            "values": [
              "JavaScript",
              "Python"
            ]
          }
        ],
        "note": "Generates code without sending a request. Supports method, headers and literal body; unsupported shell features are rejected.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "cURL command",
          "placeholder": "curl https://happytails.ai",
          "help": "Paste a cURL command. It is converted to code without sending the request. Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/curl-to-code/run",
      "api": {
        "id": "curl-to-code",
        "name": "Curl to code",
        "category": "developer-tools",
        "description": "Parse quoting, headers and body.",
        "notes": "Generates code without sending a request. Supports method, headers and literal body; unsupported shell features are rejected.",
        "human_path": "/en/developer-tools/curl-to-code/",
        "method": "POST",
        "endpoint": "/api/v1/tools/curl-to-code/run",
        "schema_url": "/api/v1/tools/curl-to-code",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "language": {
                  "type": "string",
                  "description": "Language",
                  "default": "JavaScript",
                  "enum": [
                    "JavaScript",
                    "Python"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/curl-to-code/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/curl-to-code/"
    },
    {
      "id": "file-hash",
      "category": "developer-tools",
      "built": true,
      "requirements": "SHA-256 digest and compare expected value; do not equate a matching hash with a safe file.",
      "implementation": {
        "fields": [
          {
            "key": "algorithm",
            "label": "Hash",
            "value": "SHA-256",
            "type": "select",
            "values": [
              "SHA-256",
              "SHA-384",
              "SHA-512",
              "SHA-1"
            ]
          },
          {
            "key": "expected",
            "label": "Expected hash (optional)",
            "value": "",
            "type": "text"
          }
        ],
        "files": true,
        "input": false,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/file-hash/run",
      "api": {
        "id": "file-hash",
        "name": "File hash",
        "category": "developer-tools",
        "description": "SHA-256 digest and compare expected value.",
        "notes": "",
        "human_path": "/en/developer-tools/file-hash/",
        "method": "POST",
        "endpoint": "/api/v1/tools/file-hash/run",
        "schema_url": "/api/v1/tools/file-hash",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "algorithm": {
                  "type": "string",
                  "description": "Hash",
                  "default": "SHA-256",
                  "enum": [
                    "SHA-256",
                    "SHA-384",
                    "SHA-512",
                    "SHA-1"
                  ]
                },
                "expected": {
                  "type": "string",
                  "description": "Expected hash (optional)",
                  "default": ""
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/file-hash/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/file-hash/"
    },
    {
      "id": "hex-to-text",
      "category": "developer-tools",
      "built": true,
      "requirements": "Validate even byte pairs and encoding; combine reverse conversion as a mode.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Hexadecimal bytes",
          "placeholder": "48 69",
          "help": "Separate byte values from 00 to FF with spaces or commas. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/hex-to-text/run",
      "api": {
        "id": "hex-to-text",
        "name": "Hex to text",
        "category": "developer-tools",
        "description": "Decode hexadecimal byte values into UTF-8 text.",
        "notes": "",
        "human_path": "/en/developer-tools/hex-to-text/",
        "method": "POST",
        "endpoint": "/api/v1/tools/hex-to-text/run",
        "schema_url": "/api/v1/tools/hex-to-text",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/hex-to-text/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/hex-to-text/"
    },
    {
      "id": "hmac-generator",
      "category": "developer-tools",
      "built": true,
      "requirements": "Local keys and data; algorithm selection and hex/Base64 output; no logging.",
      "implementation": {
        "fields": [
          {
            "key": "key",
            "label": "HMAC secret",
            "value": "",
            "type": "password"
          }
        ],
        "note": "HMAC-SHA-256. The secret stays in this tab.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/hmac-generator/run",
      "api": {
        "id": "hmac-generator",
        "name": "HMAC generator",
        "category": "developer-tools",
        "description": "Local keys and data.",
        "notes": "HMAC-SHA-256. The secret stays in this tab.",
        "human_path": "/en/developer-tools/hmac-generator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/hmac-generator/run",
        "schema_url": "/api/v1/tools/hmac-generator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "key": {
                  "type": "string",
                  "description": "HMAC secret",
                  "default": ""
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/hmac-generator/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/hmac-generator/"
    },
    {
      "id": "html-escape",
      "category": "developer-tools",
      "built": true,
      "requirements": "Escape/unescape modes; clarify encoding is not complete HTML sanitization.",
      "implementation": {
        "fields": [
          {
            "key": "direction",
            "label": "Direction",
            "value": "Encode",
            "type": "select",
            "values": [
              "Encode",
              "Decode"
            ]
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "HTML source",
          "placeholder": "<p>Hello <strong>world</strong>.</p>",
          "help": "Paste HTML markup, not a website URL. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/html-escape/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/html-escape/"
    },
    {
      "id": "html-formatter",
      "category": "developer-tools",
      "built": true,
      "requirements": "Format/minify with options; preserve preformatted text and template syntax scope.",
      "implementation": {
        "fields": [],
        "note": "Formatting parses your source; it does not execute it.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "HTML source",
          "placeholder": "<p>Hello <strong>world</strong>.</p>",
          "help": "Paste HTML markup, not a website URL. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/html-formatter/run",
      "api": {
        "id": "html-formatter",
        "name": "HTML formatter",
        "category": "developer-tools",
        "description": "Format/minify with options.",
        "notes": "Formatting parses your source; it does not execute it.",
        "human_path": "/en/developer-tools/html-formatter/",
        "method": "POST",
        "endpoint": "/api/v1/tools/html-formatter/run",
        "schema_url": "/api/v1/tools/html-formatter",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/html-formatter/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/html-formatter/"
    },
    {
      "id": "html-minifier",
      "category": "developer-tools",
      "built": true,
      "requirements": "Configurable safe whitespace/comment treatment; preserve preformatted content.",
      "implementation": {
        "fields": [],
        "note": "Conservatively collapses markup whitespace without running scripts. Verify visual layout after minification.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "HTML source",
          "placeholder": "<p>Hello <strong>world</strong>.</p>",
          "help": "Paste HTML markup, not a website URL. Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/html-minifier/run",
      "api": {
        "id": "html-minifier",
        "name": "HTML minifier",
        "category": "developer-tools",
        "description": "Configurable safe whitespace/comment treatment.",
        "notes": "Conservatively collapses markup whitespace without running scripts. Verify visual layout after minification.",
        "human_path": "/en/developer-tools/html-minifier/",
        "method": "POST",
        "endpoint": "/api/v1/tools/html-minifier/run",
        "schema_url": "/api/v1/tools/html-minifier",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/html-minifier/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/html-minifier/"
    },
    {
      "id": "javascript-formatter",
      "category": "developer-tools",
      "built": true,
      "requirements": "Parse and format code without executing it; define supported syntax.",
      "implementation": {
        "fields": [],
        "note": "Formatting parses your source; it does not execute it.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "JavaScript",
          "placeholder": "const message = \"Hello\";",
          "help": "Paste JavaScript source code. It is parsed as text, not executed. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/javascript-formatter/run",
      "api": {
        "id": "javascript-formatter",
        "name": "Javascript formatter",
        "category": "developer-tools",
        "description": "Parse and format code without executing it.",
        "notes": "Formatting parses your source; it does not execute it.",
        "human_path": "/en/developer-tools/javascript-formatter/",
        "method": "POST",
        "endpoint": "/api/v1/tools/javascript-formatter/run",
        "schema_url": "/api/v1/tools/javascript-formatter",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/javascript-formatter/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/javascript-formatter/"
    },
    {
      "id": "javascript-minifier",
      "category": "developer-tools",
      "built": true,
      "requirements": "Syntax-target selection; explicit mangling options; never execute supplied code.",
      "implementation": {
        "fields": [],
        "note": "Minifies without running the source code. Always test the resulting program.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "JavaScript",
          "placeholder": "const message = \"Hello\";",
          "help": "Paste JavaScript source code. It is parsed as text, not executed. Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/javascript-minifier/run",
      "api": {
        "id": "javascript-minifier",
        "name": "Javascript minifier",
        "category": "developer-tools",
        "description": "Syntax-target selection.",
        "notes": "Minifies without running the source code. Always test the resulting program.",
        "human_path": "/en/developer-tools/javascript-minifier/",
        "method": "POST",
        "endpoint": "/api/v1/tools/javascript-minifier/run",
        "schema_url": "/api/v1/tools/javascript-minifier",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/javascript-minifier/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/javascript-minifier/"
    },
    {
      "id": "jq-playground",
      "category": "developer-tools",
      "built": true,
      "requirements": "Run pinned jq version with resource limits; allow multiple output values and raw mode.",
      "implementation": {
        "fields": [
          {
            "key": "filter",
            "label": "jq filter",
            "value": ".",
            "type": "text"
          },
          {
            "key": "raw",
            "label": "Raw string output",
            "value": false,
            "type": "checkbox"
          }
        ],
        "note": "Runs pinned jq-web 0.6.2 locally in a disposable worker. 100 KB input, 1 MB output and 5-second limit. Multiple output values are preserved.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/jq-playground/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/jq-playground/"
    },
    {
      "id": "json-diff",
      "category": "developer-tools",
      "built": true,
      "requirements": "Structural rather than textual comparison; configurable object-key and array-order rules.",
      "implementation": {
        "fields": [
          {
            "key": "other",
            "label": "Second JSON",
            "value": "",
            "type": "textarea"
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "JSON",
          "placeholder": "{\"name\":\"Ada\",\"count\":2}",
          "help": "Use double-quoted property names and valid JSON values. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/json-diff/run",
      "api": {
        "id": "json-diff",
        "name": "JSON diff",
        "category": "developer-tools",
        "description": "Structural rather than textual comparison.",
        "notes": "",
        "human_path": "/en/developer-tools/json-diff/",
        "method": "POST",
        "endpoint": "/api/v1/tools/json-diff/run",
        "schema_url": "/api/v1/tools/json-diff",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "other": {
                  "type": "string",
                  "description": "Second JSON",
                  "default": ""
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/json-diff/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/json-diff/"
    },
    {
      "id": "json-escape",
      "category": "developer-tools",
      "built": true,
      "requirements": "Escape/unescape string literals with visible control-character handling.",
      "implementation": {
        "fields": [
          {
            "key": "direction",
            "label": "Direction",
            "value": "Encode",
            "type": "select",
            "values": [
              "Encode",
              "Decode"
            ]
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "JSON",
          "placeholder": "{\"name\":\"Ada\",\"count\":2}",
          "help": "Use double-quoted property names and valid JSON values. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/json-escape/run",
      "api": {
        "id": "json-escape",
        "name": "JSON escape",
        "category": "developer-tools",
        "description": "Escape/unescape string literals with visible control-character handling.",
        "notes": "",
        "human_path": "/en/developer-tools/json-escape/",
        "method": "POST",
        "endpoint": "/api/v1/tools/json-escape/run",
        "schema_url": "/api/v1/tools/json-escape",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "direction": {
                  "type": "string",
                  "description": "Direction",
                  "default": "Encode",
                  "enum": [
                    "Encode",
                    "Decode"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/json-escape/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/json-escape/"
    },
    {
      "id": "json-formatter",
      "category": "developer-tools",
      "built": true,
      "requirements": "Indent/minify with syntax errors; distinguish JSON and JSON5; no silent precision loss.",
      "implementation": {
        "fields": [
          {
            "key": "indent",
            "label": "Indent spaces",
            "value": 2,
            "type": "number"
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "JSON",
          "placeholder": "{\"name\":\"Ada\",\"count\":2}",
          "help": "Use double-quoted property names and valid JSON values. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/json-formatter/run",
      "api": {
        "id": "json-formatter",
        "name": "JSON formatter",
        "category": "developer-tools",
        "description": "Indent/minify with syntax errors.",
        "notes": "",
        "human_path": "/en/developer-tools/json-formatter/",
        "method": "POST",
        "endpoint": "/api/v1/tools/json-formatter/run",
        "schema_url": "/api/v1/tools/json-formatter",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "indent": {
                  "type": "number",
                  "description": "Indent spaces",
                  "default": 2.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "transform_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/json-formatter/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/json-formatter/"
    },
    {
      "id": "json-schema-validator",
      "category": "developer-tools",
      "built": true,
      "requirements": "Dialect-aware validation with exact instance paths and local reference resolution.",
      "implementation": {
        "fields": [
          {
            "key": "schema",
            "label": "JSON Schema (draft 7)",
            "value": "{\"type\":\"object\"}",
            "type": "textarea"
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "JSON",
          "placeholder": "{\"name\":\"Ada\",\"count\":2}",
          "help": "Use double-quoted property names and valid JSON values. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/json-schema-validator/run",
      "api": {
        "id": "json-schema-validator",
        "name": "JSON schema validator",
        "category": "developer-tools",
        "description": "Dialect-aware validation with exact instance paths and local reference resolution.",
        "notes": "",
        "human_path": "/en/developer-tools/json-schema-validator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/json-schema-validator/run",
        "schema_url": "/api/v1/tools/json-schema-validator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "schema": {
                  "type": "string",
                  "description": "JSON Schema (draft 7)",
                  "default": "{\"type\":\"object\"}"
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/json-schema-validator/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/json-schema-validator/"
    },
    {
      "id": "json-to-go",
      "category": "developer-tools",
      "built": true,
      "requirements": "Struct tags, names, nullable fields and number-type options.",
      "implementation": {
        "fields": [],
        "note": "Infers one sample; nested collections use generic types. Review missing/null fields. Java fields may need JSON mapping annotations.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "JSON",
          "placeholder": "{\"name\":\"Ada\",\"count\":2}",
          "help": "Use double-quoted property names and valid JSON values. Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/json-to-go/run",
      "api": {
        "id": "json-to-go",
        "name": "JSON to go",
        "category": "developer-tools",
        "description": "Struct tags, names, nullable fields and number-type options.",
        "notes": "Infers one sample; nested collections use generic types. Review missing/null fields. Java fields may need JSON mapping annotations.",
        "human_path": "/en/developer-tools/json-to-go/",
        "method": "POST",
        "endpoint": "/api/v1/tools/json-to-go/run",
        "schema_url": "/api/v1/tools/json-to-go",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/json-to-go/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/json-to-go/"
    },
    {
      "id": "json-to-java",
      "category": "developer-tools",
      "built": true,
      "requirements": "Class naming, lists, nullability and numeric precision options.",
      "implementation": {
        "fields": [],
        "note": "Infers one sample; nested collections use generic types. Review missing/null fields. Java fields may need JSON mapping annotations.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "JSON",
          "placeholder": "{\"name\":\"Ada\",\"count\":2}",
          "help": "Use double-quoted property names and valid JSON values. Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/json-to-java/run",
      "api": {
        "id": "json-to-java",
        "name": "JSON to java",
        "category": "developer-tools",
        "description": "Class naming, lists, nullability and numeric precision options.",
        "notes": "Infers one sample; nested collections use generic types. Review missing/null fields. Java fields may need JSON mapping annotations.",
        "human_path": "/en/developer-tools/json-to-java/",
        "method": "POST",
        "endpoint": "/api/v1/tools/json-to-java/run",
        "schema_url": "/api/v1/tools/json-to-java",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/json-to-java/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/json-to-java/"
    },
    {
      "id": "json-to-python",
      "category": "developer-tools",
      "built": true,
      "requirements": "Dataclass or TypedDict output; preserve null/boolean distinctions and identifier mapping.",
      "implementation": {
        "fields": [],
        "note": "Infers one sample. Review optional fields and nested schemas.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "JSON",
          "placeholder": "{\"name\":\"Ada\",\"count\":2}",
          "help": "Use double-quoted property names and valid JSON values. Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/json-to-python/run",
      "api": {
        "id": "json-to-python",
        "name": "JSON to python",
        "category": "developer-tools",
        "description": "Dataclass or TypedDict output.",
        "notes": "Infers one sample. Review optional fields and nested schemas.",
        "human_path": "/en/developer-tools/json-to-python/",
        "method": "POST",
        "endpoint": "/api/v1/tools/json-to-python/run",
        "schema_url": "/api/v1/tools/json-to-python",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/json-to-python/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/json-to-python/"
    },
    {
      "id": "json-to-schema",
      "category": "developer-tools",
      "built": true,
      "requirements": "Choose schema dialect; distinguish sample inference from complete validation contract.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "JSON",
          "placeholder": "{\"name\":\"Ada\",\"count\":2}",
          "help": "Use double-quoted property names and valid JSON values. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/json-to-schema/run",
      "api": {
        "id": "json-to-schema",
        "name": "JSON to schema",
        "category": "developer-tools",
        "description": "Choose schema dialect.",
        "notes": "",
        "human_path": "/en/developer-tools/json-to-schema/",
        "method": "POST",
        "endpoint": "/api/v1/tools/json-to-schema/run",
        "schema_url": "/api/v1/tools/json-to-schema",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/json-to-schema/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/json-to-schema/"
    },
    {
      "id": "json-to-typescript",
      "category": "developer-tools",
      "built": true,
      "requirements": "Infer types from samples with optional properties and unions; warn inferred schema is incomplete.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": false,
          "single": false,
          "label": "JSON",
          "placeholder": "{\"name\":\"Ada\",\"count\":2}",
          "help": "Use double-quoted property names and valid JSON values. Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/json-to-typescript/run",
      "api": {
        "id": "json-to-typescript",
        "name": "JSON to typescript",
        "category": "developer-tools",
        "description": "Infer types from samples with optional properties and unions.",
        "notes": "",
        "human_path": "/en/developer-tools/json-to-typescript/",
        "method": "POST",
        "endpoint": "/api/v1/tools/json-to-typescript/run",
        "schema_url": "/api/v1/tools/json-to-typescript",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/json-to-typescript/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/json-to-typescript/"
    },
    {
      "id": "json-validator",
      "category": "developer-tools",
      "built": true,
      "requirements": "Line/column errors and clear syntax-versus-schema validation scope.",
      "implementation": {
        "fields": [
          {
            "key": "indent",
            "label": "Indent spaces",
            "value": 2,
            "type": "number"
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "JSON",
          "placeholder": "{\"name\":\"Ada\",\"count\":2}",
          "help": "Use double-quoted property names and valid JSON values. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/json-validator/run",
      "api": {
        "id": "json-validator",
        "name": "JSON validator",
        "category": "developer-tools",
        "description": "Line/column errors and clear syntax-versus-schema validation scope.",
        "notes": "",
        "human_path": "/en/developer-tools/json-validator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/json-validator/run",
        "schema_url": "/api/v1/tools/json-validator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "indent": {
                  "type": "number",
                  "description": "Indent spaces",
                  "default": 2.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/json-validator/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/json-validator/"
    },
    {
      "id": "jsonpath-tester",
      "category": "developer-tools",
      "built": true,
      "requirements": "Show matched paths and values; identify JSONPath dialect and unsupported extensions.",
      "implementation": {
        "fields": [
          {
            "key": "path",
            "label": "JSONPath",
            "value": "$.items[*]",
            "type": "text"
          }
        ],
        "note": "Expression evaluation is disabled. Use property, index and wildcard selectors.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/jsonpath-tester/run",
      "api": {
        "id": "jsonpath-tester",
        "name": "Jsonpath tester",
        "category": "developer-tools",
        "description": "Show matched paths and values.",
        "notes": "Expression evaluation is disabled. Use property, index and wildcard selectors.",
        "human_path": "/en/developer-tools/jsonpath-tester/",
        "method": "POST",
        "endpoint": "/api/v1/tools/jsonpath-tester/run",
        "schema_url": "/api/v1/tools/jsonpath-tester",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "path": {
                  "type": "string",
                  "description": "JSONPath",
                  "default": "$.items[*]"
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/jsonpath-tester/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/jsonpath-tester/"
    },
    {
      "id": "jwt-decoder",
      "category": "developer-tools",
      "built": true,
      "requirements": "Decode header/payload locally; prominently distinguish decoding from signature verification.",
      "implementation": {
        "fields": [],
        "note": "Decoding does not verify the signature or establish trust. Tokens remain local.",
        "experience": {
          "automatic": true,
          "single": true,
          "label": "JWT",
          "placeholder": "eyJhbGciOiJub25lIn0.eyJzdWIiOiJleGFtcGxlIn0.",
          "help": "Paste all three dot-separated sections. Decoding does not verify the signature. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/jwt-decoder/run",
      "api": {
        "id": "jwt-decoder",
        "name": "JWT decoder",
        "category": "developer-tools",
        "description": "Decode header/payload locally.",
        "notes": "Decoding does not verify the signature or establish trust. Tokens remain local.",
        "human_path": "/en/developer-tools/jwt-decoder/",
        "method": "POST",
        "endpoint": "/api/v1/tools/jwt-decoder/run",
        "schema_url": "/api/v1/tools/jwt-decoder",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/jwt-decoder/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/jwt-decoder/"
    },
    {
      "id": "mock-data-generator",
      "category": "developer-tools",
      "built": true,
      "requirements": "Schema-driven seeded synthetic CSV/JSON; clearly fictional values and no real personal records.",
      "implementation": {
        "fields": [
          {
            "key": "n",
            "label": "Records",
            "value": 10,
            "type": "number"
          }
        ],
        "input": false,
        "note": "Synthetic demo records; emails use happytails.ai.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/mock-data-generator/run",
      "api": {
        "id": "mock-data-generator",
        "name": "Mock data generator",
        "category": "developer-tools",
        "description": "Schema-driven seeded synthetic CSV/JSON.",
        "notes": "Synthetic demo records; emails use happytails.ai.",
        "human_path": "/en/developer-tools/mock-data-generator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/mock-data-generator/run",
        "schema_url": "/api/v1/tools/mock-data-generator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "n": {
                  "type": "number",
                  "description": "Records",
                  "default": 10.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/mock-data-generator/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/mock-data-generator/"
    },
    {
      "id": "number-base-converter",
      "category": "developer-tools",
      "built": true,
      "requirements": "Binary/octal/decimal/hex with large-integer precision and signed-number rules.",
      "implementation": {
        "fields": [
          {
            "key": "from",
            "label": "From base",
            "value": 10,
            "type": "number"
          },
          {
            "key": "to",
            "label": "To base",
            "value": 16,
            "type": "number"
          }
        ],
        "experience": {
          "automatic": true,
          "single": true,
          "label": "Integer to convert",
          "placeholder": "255",
          "help": "Enter an integer in the selected source base. Do not include a base prefix such as 0x. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/number-base-converter/run",
      "api": {
        "id": "number-base-converter",
        "name": "Number base converter",
        "category": "developer-tools",
        "description": "Binary/octal/decimal/hex with large-integer precision and signed-number rules.",
        "notes": "",
        "human_path": "/en/developer-tools/number-base-converter/",
        "method": "POST",
        "endpoint": "/api/v1/tools/number-base-converter/run",
        "schema_url": "/api/v1/tools/number-base-converter",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "from": {
                  "type": "number",
                  "description": "From base",
                  "default": 10.0
                },
                "to": {
                  "type": "number",
                  "description": "To base",
                  "default": 16.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/number-base-converter/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/number-base-converter/"
    },
    {
      "id": "regex-tester",
      "category": "developer-tools",
      "built": true,
      "requirements": "Declare JavaScript flavor and flags; show groups; interrupt pathological expressions.",
      "implementation": {
        "fields": [
          {
            "key": "pattern",
            "label": "Regular expression",
            "value": "\\b\\w+\\b",
            "type": "text"
          },
          {
            "key": "flags",
            "label": "Flags",
            "value": "g",
            "type": "text"
          }
        ],
        "note": "JavaScript regular expressions run in a disposable worker with a 1-second limit and maximum 10,000 matches.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/regex-tester/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/regex-tester/"
    },
    {
      "id": "rsa-key-generator",
      "category": "developer-tools",
      "built": true,
      "requirements": "Local cryptographic RNG and formats with interoperability review; private-key copy lifecycle.",
      "implementation": {
        "fields": [],
        "input": false,
        "note": "2048-bit RSA-OAEP/SHA-256. Private key download is unencrypted; protect it.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/rsa-key-generator/run",
      "api": {
        "id": "rsa-key-generator",
        "name": "RSA key generator",
        "category": "developer-tools",
        "description": "Local cryptographic RNG and formats with interoperability review.",
        "notes": "2048-bit RSA-OAEP/SHA-256. Private key download is unencrypted; protect it.",
        "human_path": "/en/developer-tools/rsa-key-generator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/rsa-key-generator/run",
        "schema_url": "/api/v1/tools/rsa-key-generator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/rsa-key-generator/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/rsa-key-generator/"
    },
    {
      "id": "sql-formatter",
      "category": "developer-tools",
      "built": true,
      "requirements": "Select dialect and format without executing queries.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "SQL",
          "placeholder": "SELECT id, name FROM users;",
          "help": "Paste SQL source. This tool does not connect to a database. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/sql-formatter/run",
      "api": {
        "id": "sql-formatter",
        "name": "SQL formatter",
        "category": "developer-tools",
        "description": "Select dialect and format without executing queries.",
        "notes": "",
        "human_path": "/en/developer-tools/sql-formatter/",
        "method": "POST",
        "endpoint": "/api/v1/tools/sql-formatter/run",
        "schema_url": "/api/v1/tools/sql-formatter",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/sql-formatter/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/sql-formatter/"
    },
    {
      "id": "token-counter",
      "category": "developer-tools",
      "built": true,
      "requirements": "Explicit model/tokenizer version; local counts; no universal token-to-word conversion.",
      "implementation": {
        "fields": [
          {
            "key": "model",
            "label": "Tokenizer model",
            "value": "gpt-4o",
            "type": "select",
            "values": [
              "gpt-4o",
              "gpt-4",
              "gpt-3.5-turbo"
            ]
          }
        ],
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/token-counter/run",
      "api": {
        "id": "token-counter",
        "name": "Token counter",
        "category": "developer-tools",
        "description": "Explicit model/tokenizer version.",
        "notes": "",
        "human_path": "/en/developer-tools/token-counter/",
        "method": "POST",
        "endpoint": "/api/v1/tools/token-counter/run",
        "schema_url": "/api/v1/tools/token-counter",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "model": {
                  "type": "string",
                  "description": "Tokenizer model",
                  "default": "gpt-4o",
                  "enum": [
                    "gpt-4o",
                    "gpt-4",
                    "gpt-3.5-turbo"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/token-counter/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/token-counter/"
    },
    {
      "id": "unix-timestamp-converter",
      "category": "developer-tools",
      "built": true,
      "requirements": "Seconds versus milliseconds, UTC/local zones and explicit out-of-range handling.",
      "implementation": {
        "fields": [
          {
            "key": "direction",
            "label": "Direction",
            "value": "Timestamp to date",
            "type": "select",
            "values": [
              "Timestamp to date",
              "Date to timestamp"
            ]
          },
          {
            "key": "unit",
            "label": "Timestamp unit",
            "value": "Seconds",
            "type": "select",
            "values": [
              "Seconds",
              "Milliseconds"
            ]
          }
        ],
        "experience": {
          "automatic": true,
          "single": true,
          "label": "Unix timestamp or ISO date",
          "placeholder": "0",
          "help": "Choose the conversion direction. Timestamps use the selected seconds or milliseconds; dates need an explicit time zone. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/unix-timestamp-converter/run",
      "api": {
        "id": "unix-timestamp-converter",
        "name": "Unix timestamp converter",
        "category": "developer-tools",
        "description": "Seconds versus milliseconds, UTC/local zones and explicit out-of-range handling.",
        "notes": "",
        "human_path": "/en/developer-tools/unix-timestamp-converter/",
        "method": "POST",
        "endpoint": "/api/v1/tools/unix-timestamp-converter/run",
        "schema_url": "/api/v1/tools/unix-timestamp-converter",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "direction": {
                  "type": "string",
                  "description": "Direction",
                  "default": "Timestamp to date",
                  "enum": [
                    "Timestamp to date",
                    "Date to timestamp"
                  ]
                },
                "unit": {
                  "type": "string",
                  "description": "Timestamp unit",
                  "default": "Seconds",
                  "enum": [
                    "Seconds",
                    "Milliseconds"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/unix-timestamp-converter/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/unix-timestamp-converter/"
    },
    {
      "id": "url-encoder-decoder",
      "category": "developer-tools",
      "built": true,
      "requirements": "Full URL versus component encoding; percent errors and plus-space query semantics.",
      "implementation": {
        "fields": [
          {
            "key": "direction",
            "label": "Direction",
            "value": "Encode",
            "type": "select",
            "values": [
              "Encode",
              "Decode"
            ]
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/url-encoder-decoder/run",
      "api": {
        "id": "url-encoder-decoder",
        "name": "URL encoder decoder",
        "category": "developer-tools",
        "description": "Encode or decode a URL component.",
        "notes": "",
        "human_path": "/en/developer-tools/url-encoder-decoder/",
        "method": "POST",
        "endpoint": "/api/v1/tools/url-encoder-decoder/run",
        "schema_url": "/api/v1/tools/url-encoder-decoder",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "direction": {
                  "type": "string",
                  "description": "Direction",
                  "default": "Encode",
                  "enum": [
                    "Encode",
                    "Decode"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/url-encoder-decoder/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/url-encoder-decoder/"
    },
    {
      "id": "url-parser",
      "category": "developer-tools",
      "built": true,
      "requirements": "Show scheme, host, port, path, query and fragment; do not fetch the URL.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": true,
          "label": "URL to inspect",
          "placeholder": "https://happytails.ai/path?name=Ada#section",
          "help": "Paste a complete URL. This tool reads its parts without visiting it. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/url-parser/run",
      "api": {
        "id": "url-parser",
        "name": "URL parser",
        "category": "developer-tools",
        "description": "Show scheme, host, port, path, query and fragment.",
        "notes": "",
        "human_path": "/en/developer-tools/url-parser/",
        "method": "POST",
        "endpoint": "/api/v1/tools/url-parser/run",
        "schema_url": "/api/v1/tools/url-parser",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/url-parser/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/url-parser/"
    },
    {
      "id": "url-to-punycode",
      "category": "developer-tools",
      "built": true,
      "requirements": "Unicode domain and ASCII conversion with IDNA version stated; no domain safety assertion.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": true,
          "label": "URL or domain",
          "placeholder": "https://münich.example",
          "help": "Enter a complete URL or domain name containing international characters. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/url-to-punycode/run",
      "api": {
        "id": "url-to-punycode",
        "name": "URL to punycode",
        "category": "developer-tools",
        "description": "Unicode domain and ASCII conversion with IDNA version stated.",
        "notes": "",
        "human_path": "/en/developer-tools/url-to-punycode/",
        "method": "POST",
        "endpoint": "/api/v1/tools/url-to-punycode/run",
        "schema_url": "/api/v1/tools/url-to-punycode",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/url-to-punycode/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/url-to-punycode/"
    },
    {
      "id": "uuid-generator",
      "category": "developer-tools",
      "built": true,
      "requirements": "Declare UUID versions, secure randomness for v4 and batch copy/export limits.",
      "implementation": {
        "fields": [
          {
            "key": "n",
            "label": "UUIDs",
            "value": 1,
            "type": "number"
          }
        ],
        "input": false,
        "note": "Cryptographically random version 4 UUIDs.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/uuid-generator/run",
      "api": {
        "id": "uuid-generator",
        "name": "UUID generator",
        "category": "developer-tools",
        "description": "Declare UUID versions, secure randomness for v4 and batch copy/export limits.",
        "notes": "Cryptographically random version 4 UUIDs.",
        "human_path": "/en/developer-tools/uuid-generator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/uuid-generator/run",
        "schema_url": "/api/v1/tools/uuid-generator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "n": {
                  "type": "number",
                  "description": "UUIDs",
                  "default": 1.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/uuid-generator/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/uuid-generator/"
    },
    {
      "id": "xml-formatter",
      "category": "developer-tools",
      "built": true,
      "requirements": "Pretty-print/minify with safe parsing and explicit mixed-content handling.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "XML",
          "placeholder": "<item><name>Ada</name></item>",
          "help": "Include one root element and matching closing tags. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/xml-formatter/run",
      "api": {
        "id": "xml-formatter",
        "name": "XML formatter",
        "category": "developer-tools",
        "description": "Pretty-print/minify with safe parsing and explicit mixed-content handling.",
        "notes": "",
        "human_path": "/en/developer-tools/xml-formatter/",
        "method": "POST",
        "endpoint": "/api/v1/tools/xml-formatter/run",
        "schema_url": "/api/v1/tools/xml-formatter",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/xml-formatter/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/xml-formatter/"
    },
    {
      "id": "xml-validator",
      "category": "developer-tools",
      "built": true,
      "requirements": "Well-formedness validation; separate optional schema validation; external entities disabled.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "XML",
          "placeholder": "<item><name>Ada</name></item>",
          "help": "Include one root element and matching closing tags. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/xml-validator/run",
      "api": {
        "id": "xml-validator",
        "name": "XML validator",
        "category": "developer-tools",
        "description": "Well-formedness validation.",
        "notes": "",
        "human_path": "/en/developer-tools/xml-validator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/xml-validator/run",
        "schema_url": "/api/v1/tools/xml-validator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/xml-validator/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/xml-validator/"
    },
    {
      "id": "yaml-formatter",
      "category": "developer-tools",
      "built": true,
      "requirements": "Pin YAML version; preserve or disclose loss of comments, anchors and tags.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "YAML",
          "placeholder": "name: Ada\ncount: 2",
          "help": "Use spaces for indentation. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/yaml-formatter/run",
      "api": {
        "id": "yaml-formatter",
        "name": "YAML formatter",
        "category": "developer-tools",
        "description": "Pin YAML version.",
        "notes": "",
        "human_path": "/en/developer-tools/yaml-formatter/",
        "method": "POST",
        "endpoint": "/api/v1/tools/yaml-formatter/run",
        "schema_url": "/api/v1/tools/yaml-formatter",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/yaml-formatter/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/yaml-formatter/"
    },
    {
      "id": "yaml-validator",
      "category": "developer-tools",
      "built": true,
      "requirements": "Line/column errors, duplicate-key policy and safe parsing without arbitrary constructors.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "YAML",
          "placeholder": "name: Ada\ncount: 2",
          "help": "Use spaces for indentation. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/yaml-validator/run",
      "api": {
        "id": "yaml-validator",
        "name": "YAML validator",
        "category": "developer-tools",
        "description": "Line/column errors, duplicate-key policy and safe parsing without arbitrary constructors.",
        "notes": "",
        "human_path": "/en/developer-tools/yaml-validator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/yaml-validator/run",
        "schema_url": "/api/v1/tools/yaml-validator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/developer-tools/yaml-validator/",
      "agent_url": "https://happytails.ai/agents/en/developer-tools/yaml-validator/"
    },
    {
      "id": "internet-speed-test",
      "category": "device-tools",
      "built": true,
      "requirements": "Regional test infrastructure and reproducible download/upload/latency methodology.",
      "implementation": {
        "fields": [],
        "input": false,
        "note": "Run downloads approximately 5 MB from Cloudflare. Results vary with Wi-Fi, VPNs, browser load and server distance.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/device-tools/internet-speed-test/",
      "agent_url": "https://happytails.ai/agents/en/device-tools/internet-speed-test/"
    },
    {
      "id": "keyboard-test",
      "category": "device-tools",
      "built": true,
      "requirements": "Show key events and layout caveats; never store typed text.",
      "implementation": {
        "fields": [],
        "input": false,
        "note": "Keys are handled only while the test area has focus. Browser and OS shortcuts may be reserved.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": true
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": false,
        "name": null,
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/device-tools/keyboard-test/",
      "agent_url": "https://happytails.ai/agents/en/device-tools/keyboard-test/"
    },
    {
      "id": "microphone-test",
      "category": "device-tools",
      "built": true,
      "requirements": "User-initiated permission, local level/playback and stop controls; test browser support.",
      "implementation": {
        "fields": [],
        "input": false,
        "note": "Permission is requested only after Start. Captures stay in your browser. Stop ends device access. Browser support and available audio sources vary.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": true
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": false,
        "name": null,
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/device-tools/microphone-test/",
      "agent_url": "https://happytails.ai/agents/en/device-tools/microphone-test/"
    },
    {
      "id": "screen-test",
      "category": "device-tools",
      "built": true,
      "requirements": "Fullscreen solid colors, keyboard exit and display instructions; no guaranteed diagnosis.",
      "implementation": {
        "fields": [],
        "input": false,
        "note": "Choose a color and inspect your display. This is a visual inspection, not automatic hardware diagnosis.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": true
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": false,
        "name": null,
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/device-tools/screen-test/",
      "agent_url": "https://happytails.ai/agents/en/device-tools/screen-test/"
    },
    {
      "id": "screenshot-capture",
      "category": "device-tools",
      "built": true,
      "requirements": "Capture a still from a user-selected screen, window or tab with explicit permission where supported; stop capture tracks after use and on errors; offer local PNG download and clear unsupported-browser guidance; arbitrary remote URL capture is a separate workflow.",
      "implementation": {
        "fields": [],
        "input": false,
        "note": "Permission is requested only after Start. Captures stay in your browser. Stop ends device access. Browser support and available audio sources vary.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": true
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": false,
        "name": null,
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/device-tools/screenshot-capture/",
      "agent_url": "https://happytails.ai/agents/en/device-tools/screenshot-capture/"
    },
    {
      "id": "webcam-test",
      "category": "device-tools",
      "built": true,
      "requirements": "User-initiated camera permission, local preview and track shutdown; no recording default.",
      "implementation": {
        "fields": [],
        "input": false,
        "note": "Permission is requested only after Start. Captures stay in your browser. Stop ends device access. Browser support and available audio sources vary.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": true
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": false,
        "name": null,
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/device-tools/webcam-test/",
      "agent_url": "https://happytails.ai/agents/en/device-tools/webcam-test/"
    },
    {
      "id": "chat-with-document",
      "category": "document-tools",
      "built": true,
      "requirements": "Answer questions over an uploaded document with quoted passages and page links; show insufficient-evidence responses; delete session index on request; resist instructions embedded in documents.",
      "implementation": {
        "fields": [
          {
            "key": "question",
            "label": "Your question",
            "type": "text",
            "value": ""
          }
        ],
        "files": true,
        "accept": ".pdf,.docx,.txt",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "ai": true,
        "maxFileBytes": 20971520,
        "note": "Runs with local model weights on this website’s server. No external AI API is used. Review the result for errors. Answers from one uploaded document per request. No persistent index or chat history is stored. Source limited to 16,000 characters.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/chat-with-document/run",
      "api": {
        "id": "chat-with-document",
        "name": "Chat with document",
        "category": "document-tools",
        "description": "Ask a question about the text in a document.",
        "notes": "Runs with local model weights on this website’s server. No external AI API is used. Review the result for errors. Answers from one uploaded document per request. No persistent index or chat history is stored. Source limited to 16,000 characters.",
        "human_path": "/en/document-tools/chat-with-document/",
        "method": "POST",
        "endpoint": "/api/v1/tools/chat-with-document/run",
        "schema_url": "/api/v1/tools/chat-with-document",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "question": {
                  "type": "string",
                  "description": "Your question",
                  "default": ""
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/document-tools/chat-with-document/",
      "agent_url": "https://happytails.ai/agents/en/document-tools/chat-with-document/"
    },
    {
      "id": "document-summarizer",
      "category": "document-tools",
      "built": true,
      "requirements": "Extract text from supplied documents and summarize with page references; surface unreadable pages and missing text; distinguish summary from source quotes.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".pdf,.docx,.txt",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "ai": true,
        "maxFileBytes": 20971520,
        "note": "Runs with local model weights on this website’s server. No external AI API is used. Review the result for errors. Selectable text only; scanned documents need OCR. Source limited to 16,000 characters.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/document-summarizer/run",
      "api": {
        "id": "document-summarizer",
        "name": "Document summarizer",
        "category": "document-tools",
        "description": "Summarize readable document text with source references.",
        "notes": "Runs with local model weights on this website’s server. No external AI API is used. Review the result for errors. Selectable text only; scanned documents need OCR. Source limited to 16,000 characters.",
        "human_path": "/en/document-tools/document-summarizer/",
        "method": "POST",
        "endpoint": "/api/v1/tools/document-summarizer/run",
        "schema_url": "/api/v1/tools/document-summarizer",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/document-tools/document-summarizer/",
      "agent_url": "https://happytails.ai/agents/en/document-tools/document-summarizer/"
    },
    {
      "id": "document-translator",
      "category": "document-tools",
      "built": true,
      "requirements": "Translate extracted text with side-by-side original and translated sections; preserve headings where feasible; disclose formatting loss instead of promising perfect document reconstruction.",
      "implementation": {
        "fields": [
          {
            "key": "language",
            "label": "Translate to",
            "type": "select",
            "value": "English",
            "values": [
              "English",
              "Spanish",
              "French",
              "German",
              "Portuguese"
            ]
          }
        ],
        "files": true,
        "accept": ".pdf,.docx,.txt",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "ai": true,
        "maxFileBytes": 20971520,
        "note": "Runs with local model weights on this website’s server. No external AI API is used. Review the result for errors. Translates extracted text. Original document layout is not preserved.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/document-translator/run",
      "api": {
        "id": "document-translator",
        "name": "Document translator",
        "category": "document-tools",
        "description": "Translate readable document text into your chosen language.",
        "notes": "Runs with local model weights on this website’s server. No external AI API is used. Review the result for errors. Translates extracted text. Original document layout is not preserved.",
        "human_path": "/en/document-tools/document-translator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/document-translator/run",
        "schema_url": "/api/v1/tools/document-translator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "language": {
                  "type": "string",
                  "description": "Translate to",
                  "default": "English",
                  "enum": [
                    "English",
                    "Spanish",
                    "French",
                    "German",
                    "Portuguese"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/document-tools/document-translator/",
      "agent_url": "https://happytails.ai/agents/en/document-tools/document-translator/"
    },
    {
      "id": "docx-to-markdown",
      "category": "document-tools",
      "built": true,
      "requirements": "Extract semantics, links, lists and images; document unsupported layout and styles.",
      "implementation": {
        "fields": [],
        "files": true,
        "input": false,
        "accept": ".docx",
        "note": "Converts semantic document content. Complex layout, floating images, fields and tracked changes require review.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/document-tools/docx-to-markdown/",
      "agent_url": "https://happytails.ai/agents/en/document-tools/docx-to-markdown/"
    },
    {
      "id": "docx-to-pdf",
      "category": "document-tools",
      "built": true,
      "requirements": "Render office layout/fonts in controlled engine; test page breaks and explain fidelity limits.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".docx",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Processed by the local, self-hosted engine. No third-party conversion service is used. Rendered locally with LibreOffice. Font substitutions can change pagination. Files with external links or macros are rejected.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/docx-to-pdf/run",
      "api": {
        "id": "docx-to-pdf",
        "name": "DOCX to PDF",
        "category": "document-tools",
        "description": "Convert DOCX files to PDF with the available format settings.",
        "notes": "Processed by the local, self-hosted engine. No third-party conversion service is used. Rendered locally with LibreOffice. Font substitutions can change pagination. Files with external links or macros are rejected.",
        "human_path": "/en/document-tools/docx-to-pdf/",
        "method": "POST",
        "endpoint": "/api/v1/tools/docx-to-pdf/run",
        "schema_url": "/api/v1/tools/docx-to-pdf",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/document-tools/docx-to-pdf/",
      "agent_url": "https://happytails.ai/agents/en/document-tools/docx-to-pdf/"
    },
    {
      "id": "epub-to-pdf",
      "category": "document-tools",
      "built": true,
      "requirements": "Reflow to chosen page size with readable fonts/TOC; disclose DRM and layout limitations.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".epub",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Processed by the local, self-hosted engine. No third-party conversion service is used. Reflows unencrypted EPUB content onto A4 pages. Does not remove DRM.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/epub-to-pdf/run",
      "api": {
        "id": "epub-to-pdf",
        "name": "EPUB to PDF",
        "category": "document-tools",
        "description": "Convert EPUB files to PDF with the available format settings.",
        "notes": "Processed by the local, self-hosted engine. No third-party conversion service is used. Reflows unencrypted EPUB content onto A4 pages. Does not remove DRM.",
        "human_path": "/en/document-tools/epub-to-pdf/",
        "method": "POST",
        "endpoint": "/api/v1/tools/epub-to-pdf/run",
        "schema_url": "/api/v1/tools/epub-to-pdf",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/document-tools/epub-to-pdf/",
      "agent_url": "https://happytails.ai/agents/en/document-tools/epub-to-pdf/"
    },
    {
      "id": "excel-to-pdf",
      "category": "document-tools",
      "built": true,
      "requirements": "Choose sheets/print areas and pagination; check cached or recalculated formulas.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".xlsx",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Processed by the local, self-hosted engine. No third-party conversion service is used. Rendered locally with LibreOffice. Font substitutions can change pagination. Files with external links or macros are rejected.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/excel-to-pdf/run",
      "api": {
        "id": "excel-to-pdf",
        "name": "Excel to PDF",
        "category": "document-tools",
        "description": "Convert EXCEL files to PDF with the available format settings.",
        "notes": "Processed by the local, self-hosted engine. No third-party conversion service is used. Rendered locally with LibreOffice. Font substitutions can change pagination. Files with external links or macros are rejected.",
        "human_path": "/en/document-tools/excel-to-pdf/",
        "method": "POST",
        "endpoint": "/api/v1/tools/excel-to-pdf/run",
        "schema_url": "/api/v1/tools/excel-to-pdf",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/document-tools/excel-to-pdf/",
      "agent_url": "https://happytails.ai/agents/en/document-tools/excel-to-pdf/"
    },
    {
      "id": "image-table-to-csv",
      "category": "document-tools",
      "built": true,
      "requirements": "Recover table rows and columns from screenshots or scans; preview cell boundaries; preserve leading zeros and merged-cell ambiguity; protect spreadsheet formulas on export.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".png,.jpg,.jpeg,.webp",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "extra": true,
        "maxFileBytes": 20971520,
        "note": "Processed locally on this website’s server without an external conversion API. English OCR groups words by spacing. Simple straight tables work best; merged cells and borderless layouts need review.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/image-table-to-csv/run",
      "api": {
        "id": "image-table-to-csv",
        "name": "Image table to CSV",
        "category": "document-tools",
        "description": "Read a simple table image into draft CSV columns.",
        "notes": "Processed locally on this website’s server without an external conversion API. English OCR groups words by spacing. Simple straight tables work best; merged cells and borderless layouts need review.",
        "human_path": "/en/document-tools/image-table-to-csv/",
        "method": "POST",
        "endpoint": "/api/v1/tools/image-table-to-csv/run",
        "schema_url": "/api/v1/tools/image-table-to-csv",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/document-tools/image-table-to-csv/",
      "agent_url": "https://happytails.ai/agents/en/document-tools/image-table-to-csv/"
    },
    {
      "id": "markdown-to-pdf",
      "category": "document-tools",
      "built": true,
      "requirements": "Render defined Markdown dialect with print CSS, fonts and page breaks; sanitize HTML.",
      "implementation": {
        "fields": [],
        "note": "Readable plain-text PDF from Markdown. It does not reproduce rich layout, linked images or styled tables.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/document-tools/markdown-to-pdf/",
      "agent_url": "https://happytails.ai/agents/en/document-tools/markdown-to-pdf/"
    },
    {
      "id": "odt-to-pdf",
      "category": "document-tools",
      "built": true,
      "requirements": "Preserve supported layout and fonts; test embedded objects and page boundaries.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".odt",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Processed by the local, self-hosted engine. No third-party conversion service is used. Rendered locally with LibreOffice. Font substitutions can change pagination. Files with external links or macros are rejected.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/odt-to-pdf/run",
      "api": {
        "id": "odt-to-pdf",
        "name": "Odt to PDF",
        "category": "document-tools",
        "description": "Convert ODT files to PDF with the available format settings.",
        "notes": "Processed by the local, self-hosted engine. No third-party conversion service is used. Rendered locally with LibreOffice. Font substitutions can change pagination. Files with external links or macros are rejected.",
        "human_path": "/en/document-tools/odt-to-pdf/",
        "method": "POST",
        "endpoint": "/api/v1/tools/odt-to-pdf/run",
        "schema_url": "/api/v1/tools/odt-to-pdf",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/document-tools/odt-to-pdf/",
      "agent_url": "https://happytails.ai/agents/en/document-tools/odt-to-pdf/"
    },
    {
      "id": "powerpoint-to-pdf",
      "category": "document-tools",
      "built": true,
      "requirements": "Render slides/fonts consistently; speaker notes and hidden-slide options.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".pptx",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Processed by the local, self-hosted engine. No third-party conversion service is used. Rendered locally with LibreOffice. Font substitutions can change pagination. Files with external links or macros are rejected.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/powerpoint-to-pdf/run",
      "api": {
        "id": "powerpoint-to-pdf",
        "name": "Powerpoint to PDF",
        "category": "document-tools",
        "description": "Convert POWERPOINT files to PDF with the available format settings.",
        "notes": "Processed by the local, self-hosted engine. No third-party conversion service is used. Rendered locally with LibreOffice. Font substitutions can change pagination. Files with external links or macros are rejected.",
        "human_path": "/en/document-tools/powerpoint-to-pdf/",
        "method": "POST",
        "endpoint": "/api/v1/tools/powerpoint-to-pdf/run",
        "schema_url": "/api/v1/tools/powerpoint-to-pdf",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/document-tools/powerpoint-to-pdf/",
      "agent_url": "https://happytails.ai/agents/en/document-tools/powerpoint-to-pdf/"
    },
    {
      "id": "receipt-to-csv",
      "category": "document-tools",
      "built": true,
      "requirements": "Extract merchant, date, currency, line items and totals from receipt images; attach source crops; flag uncertain fields and arithmetic mismatch; export reviewable CSV.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".png,.jpg,.jpeg,.webp",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "extra": true,
        "maxFileBytes": 20971520,
        "note": "Processed locally on this website’s server without an external conversion API. English OCR produces reviewable source lines and amount candidates. Merchant, tax, currency, and totals are not automatically verified.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/receipt-to-csv/run",
      "api": {
        "id": "receipt-to-csv",
        "name": "Receipt to CSV",
        "category": "document-tools",
        "description": "Extract receipt lines and candidate amounts into a reviewable CSV.",
        "notes": "Processed locally on this website’s server without an external conversion API. English OCR produces reviewable source lines and amount candidates. Merchant, tax, currency, and totals are not automatically verified.",
        "human_path": "/en/document-tools/receipt-to-csv/",
        "method": "POST",
        "endpoint": "/api/v1/tools/receipt-to-csv/run",
        "schema_url": "/api/v1/tools/receipt-to-csv",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/document-tools/receipt-to-csv/",
      "agent_url": "https://happytails.ai/agents/en/document-tools/receipt-to-csv/"
    },
    {
      "id": "rtf-to-pdf",
      "category": "document-tools",
      "built": true,
      "requirements": "Render supported RTF elements safely; disclose font/layout differences.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".rtf",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Processed by the local, self-hosted engine. No third-party conversion service is used. Rendered locally with LibreOffice. Font substitutions can change pagination. Files with external links or macros are rejected.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/rtf-to-pdf/run",
      "api": {
        "id": "rtf-to-pdf",
        "name": "Rtf to PDF",
        "category": "document-tools",
        "description": "Convert RTF files to PDF with the available format settings.",
        "notes": "Processed by the local, self-hosted engine. No third-party conversion service is used. Rendered locally with LibreOffice. Font substitutions can change pagination. Files with external links or macros are rejected.",
        "human_path": "/en/document-tools/rtf-to-pdf/",
        "method": "POST",
        "endpoint": "/api/v1/tools/rtf-to-pdf/run",
        "schema_url": "/api/v1/tools/rtf-to-pdf",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/document-tools/rtf-to-pdf/",
      "agent_url": "https://happytails.ai/agents/en/document-tools/rtf-to-pdf/"
    },
    {
      "id": "text-to-pdf",
      "category": "document-tools",
      "built": true,
      "requirements": "Encoding, font, page margins and wrapping; simple downloadable PDF.",
      "implementation": {
        "fields": [],
        "note": "Basic Latin text PDF with selectable text. Unsupported characters produce an error instead of silently disappearing.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/text-to-pdf/run",
      "api": {
        "id": "text-to-pdf",
        "name": "Text to PDF",
        "category": "document-tools",
        "description": "Create a PDF from plain text.",
        "notes": "Basic Latin text PDF with selectable text. Unsupported characters produce an error instead of silently disappearing.",
        "human_path": "/en/document-tools/text-to-pdf/",
        "method": "POST",
        "endpoint": "/api/v1/tools/text-to-pdf/run",
        "schema_url": "/api/v1/tools/text-to-pdf",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/document-tools/text-to-pdf/",
      "agent_url": "https://happytails.ai/agents/en/document-tools/text-to-pdf/"
    },
    {
      "id": "citation-generator",
      "category": "education-tools",
      "built": true,
      "requirements": "Verified style versions and source metadata; manual entry first; do not invent missing bibliographic facts.",
      "implementation": {
        "fields": [
          {
            "key": "style",
            "label": "Style",
            "value": "APA",
            "type": "select",
            "values": [
              "APA",
              "MLA",
              "Chicago"
            ]
          },
          {
            "key": "author",
            "label": "Author",
            "value": "",
            "type": "text"
          },
          {
            "key": "organization",
            "label": "Organization (if no author)",
            "value": "",
            "type": "text"
          },
          {
            "key": "date",
            "label": "Publication date",
            "value": "",
            "type": "text"
          },
          {
            "key": "title",
            "label": "Page title",
            "value": "",
            "type": "text"
          },
          {
            "key": "site",
            "label": "Website name",
            "value": "",
            "type": "text"
          }
        ],
        "note": "Basic webpage reference formatting. Supply verified source metadata; this does not verify sources or cover every reference type.",
        "experience": {
          "automatic": false,
          "single": true,
          "label": "Source URL",
          "placeholder": "https://happytails.ai/article",
          "help": "Enter the webpage URL, then supply the source title, author and publication details below. Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/citation-generator/run",
      "api": {
        "id": "citation-generator",
        "name": "Citation generator",
        "category": "education-tools",
        "description": "Verified style versions and source metadata.",
        "notes": "Basic webpage reference formatting. Supply verified source metadata; this does not verify sources or cover every reference type.",
        "human_path": "/en/education-tools/citation-generator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/citation-generator/run",
        "schema_url": "/api/v1/tools/citation-generator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "style": {
                  "type": "string",
                  "description": "Style",
                  "default": "APA",
                  "enum": [
                    "APA",
                    "MLA",
                    "Chicago"
                  ]
                },
                "author": {
                  "type": "string",
                  "description": "Author",
                  "default": ""
                },
                "organization": {
                  "type": "string",
                  "description": "Organization (if no author)",
                  "default": ""
                },
                "date": {
                  "type": "string",
                  "description": "Publication date",
                  "default": ""
                },
                "title": {
                  "type": "string",
                  "description": "Page title",
                  "default": ""
                },
                "site": {
                  "type": "string",
                  "description": "Website name",
                  "default": ""
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/education-tools/citation-generator/",
      "agent_url": "https://happytails.ai/agents/en/education-tools/citation-generator/"
    },
    {
      "id": "final-grade",
      "category": "education-tools",
      "built": true,
      "requirements": "Required final-exam score from weights; show impossible targets without clamping.",
      "implementation": {
        "fields": [
          {
            "key": "current",
            "label": "Current grade (%)",
            "value": 80,
            "type": "number"
          },
          {
            "key": "target",
            "label": "Target grade (%)",
            "value": 85,
            "type": "number"
          },
          {
            "key": "weight",
            "label": "Final exam weight (%)",
            "value": 30,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/final-grade/run",
      "api": {
        "id": "final-grade",
        "name": "Final grade",
        "category": "education-tools",
        "description": "Find the final-exam score needed to reach a target course grade.",
        "notes": "",
        "human_path": "/en/education-tools/final-grade/",
        "method": "POST",
        "endpoint": "/api/v1/tools/final-grade/run",
        "schema_url": "/api/v1/tools/final-grade",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "current": {
                  "type": "number",
                  "description": "Current grade (%)",
                  "default": 80.0
                },
                "target": {
                  "type": "number",
                  "description": "Target grade (%)",
                  "default": 85.0
                },
                "weight": {
                  "type": "number",
                  "description": "Final exam weight (%)",
                  "default": 30.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/education-tools/final-grade/",
      "agent_url": "https://happytails.ai/agents/en/education-tools/final-grade/"
    },
    {
      "id": "flashcard-maker",
      "category": "education-tools",
      "built": true,
      "requirements": "CSV/TSV import, printable cards and local study; opt-in storage only.",
      "implementation": {
        "fields": [],
        "input": false,
        "note": "Cards stay in this tab. Keep your original tab-separated text to reuse the set.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": true
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": false,
        "name": null,
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/education-tools/flashcard-maker/",
      "agent_url": "https://happytails.ai/agents/en/education-tools/flashcard-maker/"
    },
    {
      "id": "gpa-calculator",
      "category": "education-tools",
      "built": true,
      "requirements": "User-selected grading system and credits; explicit conversion rules.",
      "implementation": {
        "fields": [],
        "note": "One score,weight pair per line. For GPA use numeric grade points and course credits.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Grade points and credits",
          "placeholder": "3,3\n4,3",
          "help": "Add one numeric grade-point,credit pair per line. Convert letter grades using your institution’s scale first. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/gpa-calculator/run",
      "api": {
        "id": "gpa-calculator",
        "name": "Gpa calculator",
        "category": "education-tools",
        "description": "Calculate a weighted GPA from grade points and course credits.",
        "notes": "One score,weight pair per line. For GPA use numeric grade points and course credits.",
        "human_path": "/en/education-tools/gpa-calculator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/gpa-calculator/run",
        "schema_url": "/api/v1/tools/gpa-calculator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/education-tools/gpa-calculator/",
      "agent_url": "https://happytails.ai/agents/en/education-tools/gpa-calculator/"
    },
    {
      "id": "grade-calculator",
      "category": "education-tools",
      "built": true,
      "requirements": "Weighted and point-based grades; editable thresholds and no implied universal grading system.",
      "implementation": {
        "fields": [],
        "note": "One score,weight pair per line. For GPA use numeric grade points and course credits.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Scores and weights",
          "placeholder": "80,1\n90,1",
          "help": "Add one score,weight pair per line. Use the same score scale throughout. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/grade-calculator/run",
      "api": {
        "id": "grade-calculator",
        "name": "Grade calculator",
        "category": "education-tools",
        "description": "Calculate a weighted average from scores and their weights.",
        "notes": "One score,weight pair per line. For GPA use numeric grade points and course credits.",
        "human_path": "/en/education-tools/grade-calculator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/grade-calculator/run",
        "schema_url": "/api/v1/tools/grade-calculator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/education-tools/grade-calculator/",
      "agent_url": "https://happytails.ai/agents/en/education-tools/grade-calculator/"
    },
    {
      "id": "notes-to-flashcards",
      "category": "education-tools",
      "built": true,
      "requirements": "Generate editable question-answer pairs from supplied notes; cite source passages; export CSV for study apps; validate factual coverage and avoid unsupported answers.",
      "implementation": {
        "fields": [],
        "files": false,
        "accept": "",
        "multiple": false,
        "input": true,
        "processing": "Server required",
        "native": true,
        "ai": true,
        "maxFileBytes": 20971520,
        "note": "Runs with local model weights on this website’s server. No external AI API is used. Review the result for errors. At most 16,000 source characters. Generated suggestions require your review.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/notes-to-flashcards/run",
      "api": {
        "id": "notes-to-flashcards",
        "name": "Notes to flashcards",
        "category": "education-tools",
        "description": "Turn short notes into study cards linked to source sentences.",
        "notes": "Runs with local model weights on this website’s server. No external AI API is used. Review the result for errors. At most 16,000 source characters. Generated suggestions require your review.",
        "human_path": "/en/education-tools/notes-to-flashcards/",
        "method": "POST",
        "endpoint": "/api/v1/tools/notes-to-flashcards/run",
        "schema_url": "/api/v1/tools/notes-to-flashcards",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 0,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/education-tools/notes-to-flashcards/",
      "agent_url": "https://happytails.ai/agents/en/education-tools/notes-to-flashcards/"
    },
    {
      "id": "quiz-from-notes",
      "category": "education-tools",
      "built": true,
      "requirements": "Create editable quiz questions from notes with answer explanations and source references; check that exactly one correct answer exists for single-choice mode.",
      "implementation": {
        "fields": [],
        "files": false,
        "accept": "",
        "multiple": false,
        "input": true,
        "processing": "Server required",
        "native": true,
        "ai": true,
        "maxFileBytes": 20971520,
        "note": "Runs with local model weights on this website’s server. No external AI API is used. Review the result for errors. At most 16,000 source characters. Generated suggestions require your review.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/quiz-from-notes/run",
      "api": {
        "id": "quiz-from-notes",
        "name": "Quiz from notes",
        "category": "education-tools",
        "description": "Draft multiple-choice questions supported by your notes.",
        "notes": "Runs with local model weights on this website’s server. No external AI API is used. Review the result for errors. At most 16,000 source characters. Generated suggestions require your review.",
        "human_path": "/en/education-tools/quiz-from-notes/",
        "method": "POST",
        "endpoint": "/api/v1/tools/quiz-from-notes/run",
        "schema_url": "/api/v1/tools/quiz-from-notes",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 0,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/education-tools/quiz-from-notes/",
      "agent_url": "https://happytails.ai/agents/en/education-tools/quiz-from-notes/"
    },
    {
      "id": "typing-test",
      "category": "education-tools",
      "built": true,
      "requirements": "Language-specific text, accuracy and consistent WPM formula; keyboard accessibility.",
      "implementation": {
        "fields": [],
        "input": false,
        "note": "Typing speed uses five characters per word. Accuracy compares characters with the supplied passage. Pasted text does not receive a timed speed score.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": true
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": false,
        "name": null,
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/education-tools/typing-test/",
      "agent_url": "https://happytails.ai/agents/en/education-tools/typing-test/"
    },
    {
      "id": "dkim-checker",
      "category": "email-tools",
      "built": true,
      "requirements": "Domain plus selector lookup; explain a record alone does not validate a specific message.",
      "implementation": {
        "fields": [
          {
            "key": "selector",
            "label": "DKIM selector",
            "value": "default",
            "type": "text"
          }
        ],
        "processing": "Server required",
        "note": "Uses the local diagnostic server to contact the supplied public host or DNS/RDAP provider. Only public internet addresses are permitted; requests time out and redirects are bounded.",
        "experience": {
          "automatic": false,
          "single": true,
          "label": "Domain name",
          "placeholder": "happytails.ai",
          "help": "Enter one domain name without https://, a path or a port.",
          "action": "Check domain"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/dkim-checker/run",
      "api": {
        "id": "dkim-checker",
        "name": "DKIM checker",
        "category": "email-tools",
        "description": "Domain plus selector lookup.",
        "notes": "Uses the local diagnostic server to contact the supplied public host or DNS/RDAP provider. Only public internet addresses are permitted; requests time out and redirects are bounded.",
        "human_path": "/en/email-tools/dkim-checker/",
        "method": "POST",
        "endpoint": "/api/v1/tools/dkim-checker/run",
        "schema_url": "/api/v1/tools/dkim-checker",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "selector": {
                  "type": "string",
                  "description": "DKIM selector",
                  "default": "default"
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; contacts public network services",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": null
        }
      },
      "agent_processing": "Server; contacts public network services",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/email-tools/dkim-checker/",
      "agent_url": "https://happytails.ai/agents/en/email-tools/dkim-checker/"
    },
    {
      "id": "dmarc-checker",
      "category": "email-tools",
      "built": true,
      "requirements": "Parse policy, reporting addresses and inheritance; report check timestamp.",
      "implementation": {
        "fields": [],
        "processing": "Server required",
        "note": "Uses the local diagnostic server to contact the supplied public host or DNS/RDAP provider. Only public internet addresses are permitted; requests time out and redirects are bounded.",
        "experience": {
          "automatic": false,
          "single": true,
          "label": "Domain name",
          "placeholder": "happytails.ai",
          "help": "Enter one domain name without https://, a path or a port.",
          "action": "Check domain"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/dmarc-checker/run",
      "api": {
        "id": "dmarc-checker",
        "name": "DMARC checker",
        "category": "email-tools",
        "description": "Parse policy, reporting addresses and inheritance.",
        "notes": "Uses the local diagnostic server to contact the supplied public host or DNS/RDAP provider. Only public internet addresses are permitted; requests time out and redirects are bounded.",
        "human_path": "/en/email-tools/dmarc-checker/",
        "method": "POST",
        "endpoint": "/api/v1/tools/dmarc-checker/run",
        "schema_url": "/api/v1/tools/dmarc-checker",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; contacts public network services",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": null
        }
      },
      "agent_processing": "Server; contacts public network services",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/email-tools/dmarc-checker/",
      "agent_url": "https://happytails.ai/agents/en/email-tools/dmarc-checker/"
    },
    {
      "id": "email-header-analyzer",
      "category": "email-tools",
      "built": true,
      "requirements": "Local parsing of hops and authentication results; distinguish reported versus independently verified claims.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/email-header-analyzer/run",
      "api": {
        "id": "email-header-analyzer",
        "name": "Email header analyzer",
        "category": "email-tools",
        "description": "Local parsing of hops and authentication results.",
        "notes": "",
        "human_path": "/en/email-tools/email-header-analyzer/",
        "method": "POST",
        "endpoint": "/api/v1/tools/email-header-analyzer/run",
        "schema_url": "/api/v1/tools/email-header-analyzer",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/email-tools/email-header-analyzer/",
      "agent_url": "https://happytails.ai/agents/en/email-tools/email-header-analyzer/"
    },
    {
      "id": "email-signature-generator",
      "category": "email-tools",
      "built": true,
      "requirements": "Accessible HTML/plain text output with previews; email-client rendering limitations.",
      "implementation": {
        "fields": [
          {
            "key": "name",
            "label": "Name",
            "value": "",
            "type": "text"
          },
          {
            "key": "role",
            "label": "Role",
            "value": "",
            "type": "text"
          },
          {
            "key": "company",
            "label": "Company",
            "value": "",
            "type": "text"
          },
          {
            "key": "email",
            "label": "Email",
            "value": "",
            "type": "text"
          },
          {
            "key": "phone",
            "label": "Phone",
            "value": "",
            "type": "text"
          }
        ],
        "input": false,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/email-signature-generator/run",
      "api": {
        "id": "email-signature-generator",
        "name": "Email signature generator",
        "category": "email-tools",
        "description": "Create a simple HTML email signature with your contact details.",
        "notes": "",
        "human_path": "/en/email-tools/email-signature-generator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/email-signature-generator/run",
        "schema_url": "/api/v1/tools/email-signature-generator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "name": {
                  "type": "string",
                  "description": "Name",
                  "default": ""
                },
                "role": {
                  "type": "string",
                  "description": "Role",
                  "default": ""
                },
                "company": {
                  "type": "string",
                  "description": "Company",
                  "default": ""
                },
                "email": {
                  "type": "string",
                  "description": "Email",
                  "default": ""
                },
                "phone": {
                  "type": "string",
                  "description": "Phone",
                  "default": ""
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/email-tools/email-signature-generator/",
      "agent_url": "https://happytails.ai/agents/en/email-tools/email-signature-generator/"
    },
    {
      "id": "eml-to-pdf",
      "category": "email-tools",
      "built": true,
      "requirements": "Render headers/body and attachment manifest; sanitize HTML, do not fetch trackers.",
      "implementation": {
        "fields": [],
        "files": true,
        "input": false,
        "accept": ".eml",
        "note": "Exports plain-text message content; does not execute HTML or embed attachments.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/eml-to-pdf/run",
      "api": {
        "id": "eml-to-pdf",
        "name": "Eml to PDF",
        "category": "email-tools",
        "description": "Render headers/body and attachment manifest.",
        "notes": "Exports plain-text message content; does not execute HTML or embed attachments.",
        "human_path": "/en/email-tools/eml-to-pdf/",
        "method": "POST",
        "endpoint": "/api/v1/tools/eml-to-pdf/run",
        "schema_url": "/api/v1/tools/eml-to-pdf",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/email-tools/eml-to-pdf/",
      "agent_url": "https://happytails.ai/agents/en/email-tools/eml-to-pdf/"
    },
    {
      "id": "eml-viewer",
      "category": "email-tools",
      "built": true,
      "requirements": "Local MIME parsing with disabled remote assets and attachment listing.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".eml",
        "note": "Reads the message locally. HTML is shown as source; remote images and scripts are never loaded.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/eml-viewer/run",
      "api": {
        "id": "eml-viewer",
        "name": "Eml viewer",
        "category": "email-tools",
        "description": "Local MIME parsing with disabled remote assets and attachment listing.",
        "notes": "Reads the message locally. HTML is shown as source; remote images and scripts are never loaded.",
        "human_path": "/en/email-tools/eml-viewer/",
        "method": "POST",
        "endpoint": "/api/v1/tools/eml-viewer/run",
        "schema_url": "/api/v1/tools/eml-viewer",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/email-tools/eml-viewer/",
      "agent_url": "https://happytails.ai/agents/en/email-tools/eml-viewer/"
    },
    {
      "id": "spf-checker",
      "category": "email-tools",
      "built": true,
      "requirements": "DNS lookups, include-chain limits and findings; never infer delivery guarantee.",
      "implementation": {
        "fields": [],
        "processing": "Server required",
        "note": "Uses the local diagnostic server to contact the supplied public host or DNS/RDAP provider. Only public internet addresses are permitted; requests time out and redirects are bounded.",
        "experience": {
          "automatic": false,
          "single": true,
          "label": "Domain name",
          "placeholder": "happytails.ai",
          "help": "Enter one domain name without https://, a path or a port.",
          "action": "Check domain"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/spf-checker/run",
      "api": {
        "id": "spf-checker",
        "name": "SPF checker",
        "category": "email-tools",
        "description": "DNS lookups, include-chain limits and findings.",
        "notes": "Uses the local diagnostic server to contact the supplied public host or DNS/RDAP provider. Only public internet addresses are permitted; requests time out and redirects are bounded.",
        "human_path": "/en/email-tools/spf-checker/",
        "method": "POST",
        "endpoint": "/api/v1/tools/spf-checker/run",
        "schema_url": "/api/v1/tools/spf-checker",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; contacts public network services",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": null
        }
      },
      "agent_processing": "Server; contacts public network services",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/email-tools/spf-checker/",
      "agent_url": "https://happytails.ai/agents/en/email-tools/spf-checker/"
    },
    {
      "id": "compound-interest",
      "category": "finance-tools",
      "built": true,
      "requirements": "Contribution timing, compounding frequency and inflation assumptions; independently verify formulas.",
      "implementation": {
        "fields": [
          {
            "key": "principal",
            "label": "Starting amount",
            "value": 1000,
            "type": "number"
          },
          {
            "key": "rate",
            "label": "Nominal annual rate (%)",
            "value": 5,
            "type": "number"
          },
          {
            "key": "years",
            "label": "Years",
            "value": 10,
            "type": "number"
          },
          {
            "key": "n",
            "label": "Compounds per year",
            "value": 12,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/compound-interest/run",
      "api": {
        "id": "compound-interest",
        "name": "Compound interest",
        "category": "finance-tools",
        "description": "Calculate growth from regular compounding at a fixed rate.",
        "notes": "",
        "human_path": "/en/finance-tools/compound-interest/",
        "method": "POST",
        "endpoint": "/api/v1/tools/compound-interest/run",
        "schema_url": "/api/v1/tools/compound-interest",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "principal": {
                  "type": "number",
                  "description": "Starting amount",
                  "default": 1000.0
                },
                "rate": {
                  "type": "number",
                  "description": "Nominal annual rate (%)",
                  "default": 5.0
                },
                "years": {
                  "type": "number",
                  "description": "Years",
                  "default": 10.0
                },
                "n": {
                  "type": "number",
                  "description": "Compounds per year",
                  "default": 12.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/finance-tools/compound-interest/",
      "agent_url": "https://happytails.ai/agents/en/finance-tools/compound-interest/"
    },
    {
      "id": "currency-converter",
      "category": "finance-tools",
      "built": true,
      "requirements": "Licensed rate feed, timestamp and source; distinguish indicative from actual transfer rates.",
      "implementation": {
        "fields": [
          {
            "key": "source",
            "label": "From currency",
            "value": "EUR",
            "type": "text"
          },
          {
            "key": "target",
            "label": "To currency",
            "value": "USD",
            "type": "text"
          }
        ],
        "processing": "Server required",
        "note": "Fetches dated reference exchange rates from Frankfurter via the local server. Not a live trading quote; fees are excluded.",
        "experience": {
          "automatic": false,
          "single": true,
          "label": "Amount",
          "placeholder": "100",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert amount"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/currency-converter/run",
      "api": {
        "id": "currency-converter",
        "name": "Currency converter",
        "category": "finance-tools",
        "description": "Licensed rate feed, timestamp and source.",
        "notes": "Fetches dated reference exchange rates from Frankfurter via the local server. Not a live trading quote; fees are excluded.",
        "human_path": "/en/finance-tools/currency-converter/",
        "method": "POST",
        "endpoint": "/api/v1/tools/currency-converter/run",
        "schema_url": "/api/v1/tools/currency-converter",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "source": {
                  "type": "string",
                  "description": "From currency",
                  "default": "EUR"
                },
                "target": {
                  "type": "string",
                  "description": "To currency",
                  "default": "USD"
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; contacts public network services",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": null
        }
      },
      "agent_processing": "Server; contacts public network services",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/finance-tools/currency-converter/",
      "agent_url": "https://happytails.ai/agents/en/finance-tools/currency-converter/"
    },
    {
      "id": "loan-payment",
      "category": "finance-tools",
      "built": true,
      "requirements": "Rate convention, term and fees; amortization and rounding reconciliation.",
      "implementation": {
        "fields": [
          {
            "key": "principal",
            "label": "Principal",
            "value": 200000,
            "type": "number"
          },
          {
            "key": "rate",
            "label": "Annual interest (%)",
            "value": 5,
            "type": "number"
          },
          {
            "key": "years",
            "label": "Term in years",
            "value": 30,
            "type": "number"
          }
        ],
        "input": false,
        "note": "Fixed nominal rate, monthly payments. Excludes fees, taxes and insurance.",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/loan-payment/run",
      "api": {
        "id": "loan-payment",
        "name": "Loan payment",
        "category": "finance-tools",
        "description": "Estimate monthly payments on a fixed-rate loan.",
        "notes": "Fixed nominal rate, monthly payments. Excludes fees, taxes and insurance.",
        "human_path": "/en/finance-tools/loan-payment/",
        "method": "POST",
        "endpoint": "/api/v1/tools/loan-payment/run",
        "schema_url": "/api/v1/tools/loan-payment",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "principal": {
                  "type": "number",
                  "description": "Principal",
                  "default": 200000.0
                },
                "rate": {
                  "type": "number",
                  "description": "Annual interest (%)",
                  "default": 5.0
                },
                "years": {
                  "type": "number",
                  "description": "Term in years",
                  "default": 30.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/finance-tools/loan-payment/",
      "agent_url": "https://happytails.ai/agents/en/finance-tools/loan-payment/"
    },
    {
      "id": "mortgage-payment",
      "category": "finance-tools",
      "built": true,
      "requirements": "Country-specific interest conventions, taxes/insurance and disclosures require editorial ownership.",
      "implementation": {
        "fields": [
          {
            "key": "principal",
            "label": "Principal",
            "value": 200000,
            "type": "number"
          },
          {
            "key": "rate",
            "label": "Annual interest (%)",
            "value": 5,
            "type": "number"
          },
          {
            "key": "years",
            "label": "Term in years",
            "value": 30,
            "type": "number"
          }
        ],
        "input": false,
        "note": "Fixed nominal rate, monthly payments. Excludes fees, taxes and insurance.",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/mortgage-payment/run",
      "api": {
        "id": "mortgage-payment",
        "name": "Mortgage payment",
        "category": "finance-tools",
        "description": "Estimate principal and interest payments for a fixed-rate mortgage.",
        "notes": "Fixed nominal rate, monthly payments. Excludes fees, taxes and insurance.",
        "human_path": "/en/finance-tools/mortgage-payment/",
        "method": "POST",
        "endpoint": "/api/v1/tools/mortgage-payment/run",
        "schema_url": "/api/v1/tools/mortgage-payment",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "principal": {
                  "type": "number",
                  "description": "Principal",
                  "default": 200000.0
                },
                "rate": {
                  "type": "number",
                  "description": "Annual interest (%)",
                  "default": 5.0
                },
                "years": {
                  "type": "number",
                  "description": "Term in years",
                  "default": 30.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/finance-tools/mortgage-payment/",
      "agent_url": "https://happytails.ai/agents/en/finance-tools/mortgage-payment/"
    },
    {
      "id": "savings-goal",
      "category": "finance-tools",
      "built": true,
      "requirements": "Contribution timing and rate assumptions with transparent deterministic projection.",
      "implementation": {
        "fields": [
          {
            "key": "goal",
            "label": "Target balance",
            "value": 10000,
            "type": "number"
          },
          {
            "key": "start",
            "label": "Starting balance",
            "value": 1000,
            "type": "number"
          },
          {
            "key": "months",
            "label": "Months",
            "value": 24,
            "type": "number"
          },
          {
            "key": "rate",
            "label": "Annual nominal rate (%)",
            "value": 4,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/savings-goal/run",
      "api": {
        "id": "savings-goal",
        "name": "Savings goal",
        "category": "finance-tools",
        "description": "Estimate the monthly contribution needed to reach a savings goal.",
        "notes": "",
        "human_path": "/en/finance-tools/savings-goal/",
        "method": "POST",
        "endpoint": "/api/v1/tools/savings-goal/run",
        "schema_url": "/api/v1/tools/savings-goal",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "goal": {
                  "type": "number",
                  "description": "Target balance",
                  "default": 10000.0
                },
                "start": {
                  "type": "number",
                  "description": "Starting balance",
                  "default": 1000.0
                },
                "months": {
                  "type": "number",
                  "description": "Months",
                  "default": 24.0
                },
                "rate": {
                  "type": "number",
                  "description": "Annual nominal rate (%)",
                  "default": 4.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/finance-tools/savings-goal/",
      "agent_url": "https://happytails.ai/agents/en/finance-tools/savings-goal/"
    },
    {
      "id": "font-inspector",
      "category": "font-tools",
      "built": true,
      "requirements": "Read TTF, OTF, WOFF and WOFF2; report family, style, glyph count, character coverage, variable axes and embedding flags.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".ttf,.otf,.woff,.woff2",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "expansion": true,
        "maxFileBytes": 20971520,
        "note": "Processed on our server with no external conversion service. Reads font metadata and coverage. Embedding flags are metadata, not legal permission. Check the font license before reuse.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/font-inspector/run",
      "api": {
        "id": "font-inspector",
        "name": "Font inspector",
        "category": "font-tools",
        "description": "Inspect a font’s names, glyph coverage and format.",
        "notes": "Processed on our server with no external conversion service. Reads font metadata and coverage. Embedding flags are metadata, not legal permission. Check the font license before reuse.",
        "human_path": "/en/font-tools/font-inspector/",
        "method": "POST",
        "endpoint": "/api/v1/tools/font-inspector/run",
        "schema_url": "/api/v1/tools/font-inspector",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/font-tools/font-inspector/",
      "agent_url": "https://happytails.ai/agents/en/font-tools/font-inspector/"
    },
    {
      "id": "ttf-to-woff2",
      "category": "font-tools",
      "built": true,
      "requirements": "Preserve glyph outlines, character mappings, layout tables and metrics; do not claim conversion grants a web embedding license.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".ttf",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "expansion": true,
        "maxFileBytes": 20971520,
        "note": "Processed on our server with no external conversion service. Preserves TrueType glyphs and layout tables. Check that your font license permits web embedding.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/ttf-to-woff2/run",
      "api": {
        "id": "ttf-to-woff2",
        "name": "TTF to WOFF2",
        "category": "font-tools",
        "description": "Compress a TrueType font into a WOFF2 web font.",
        "notes": "Processed on our server with no external conversion service. Preserves TrueType glyphs and layout tables. Check that your font license permits web embedding.",
        "human_path": "/en/font-tools/ttf-to-woff2/",
        "method": "POST",
        "endpoint": "/api/v1/tools/ttf-to-woff2/run",
        "schema_url": "/api/v1/tools/ttf-to-woff2",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/font-tools/ttf-to-woff2/",
      "agent_url": "https://happytails.ai/agents/en/font-tools/ttf-to-woff2/"
    },
    {
      "id": "woff2-to-ttf",
      "category": "font-tools",
      "built": true,
      "requirements": "Reject CFF-based fonts rather than relabeling them as TTF; preserve glyphs, mapping and metrics.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".woff2",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "expansion": true,
        "maxFileBytes": 20971520,
        "note": "Processed on our server with no external conversion service. Only TrueType-outline WOFF2 is supported. CFF-outline fonts require an OTF output and are rejected here.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/woff2-to-ttf/run",
      "api": {
        "id": "woff2-to-ttf",
        "name": "WOFF2 to TTF",
        "category": "font-tools",
        "description": "Unpack a TrueType-based WOFF2 font into TTF.",
        "notes": "Processed on our server with no external conversion service. Only TrueType-outline WOFF2 is supported. CFF-outline fonts require an OTF output and are rejected here.",
        "human_path": "/en/font-tools/woff2-to-ttf/",
        "method": "POST",
        "endpoint": "/api/v1/tools/woff2-to-ttf/run",
        "schema_url": "/api/v1/tools/woff2-to-ttf",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/font-tools/woff2-to-ttf/",
      "agent_url": "https://happytails.ai/agents/en/font-tools/woff2-to-ttf/"
    },
    {
      "id": "coordinate-converter",
      "category": "geo-tools",
      "built": true,
      "requirements": "Decimal degrees and degrees/minutes/seconds; axis order and datum explicit.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": true,
          "label": "Coordinates",
          "placeholder": "38.7, -9.1",
          "help": "Enter latitude, then longitude, in decimal degrees. Use a minus sign for south or west. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/coordinate-converter/run",
      "api": {
        "id": "coordinate-converter",
        "name": "Coordinate converter",
        "category": "geo-tools",
        "description": "Convert decimal latitude and longitude to degrees, minutes and seconds.",
        "notes": "",
        "human_path": "/en/geo-tools/coordinate-converter/",
        "method": "POST",
        "endpoint": "/api/v1/tools/coordinate-converter/run",
        "schema_url": "/api/v1/tools/coordinate-converter",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/geo-tools/coordinate-converter/",
      "agent_url": "https://happytails.ai/agents/en/geo-tools/coordinate-converter/"
    },
    {
      "id": "distance-between-coordinates",
      "category": "geo-tools",
      "built": true,
      "requirements": "Geodesic surface distance with units and method; distinguish driving routes.",
      "implementation": {
        "fields": [
          {
            "key": "end",
            "label": "Destination latitude,longitude",
            "value": "48.8566,2.3522",
            "type": "text"
          }
        ],
        "experience": {
          "automatic": true,
          "single": true,
          "label": "Starting latitude, longitude",
          "placeholder": "38.7, -9.1",
          "help": "Enter decimal degrees. Set the destination in the field below. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/distance-between-coordinates/run",
      "api": {
        "id": "distance-between-coordinates",
        "name": "Distance between coordinates",
        "category": "geo-tools",
        "description": "Geodesic surface distance with units and method.",
        "notes": "",
        "human_path": "/en/geo-tools/distance-between-coordinates/",
        "method": "POST",
        "endpoint": "/api/v1/tools/distance-between-coordinates/run",
        "schema_url": "/api/v1/tools/distance-between-coordinates",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "end": {
                  "type": "string",
                  "description": "Destination latitude,longitude",
                  "default": "48.8566,2.3522"
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/geo-tools/distance-between-coordinates/",
      "agent_url": "https://happytails.ai/agents/en/geo-tools/distance-between-coordinates/"
    },
    {
      "id": "geojson-viewer",
      "category": "geo-tools",
      "built": true,
      "requirements": "Local geometry preview, validation and bbox; optional basemap network requests disclosed.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": false,
          "single": false,
          "label": "GeoJSON",
          "placeholder": "{\"type\":\"FeatureCollection\",\"features\":[]}",
          "help": "Paste a valid GeoJSON object. Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/geo-tools/geojson-viewer/",
      "agent_url": "https://happytails.ai/agents/en/geo-tools/geojson-viewer/"
    },
    {
      "id": "gpx-to-kml",
      "category": "geo-tools",
      "built": true,
      "requirements": "Tracks, waypoints, elevation and time preservation with conversion report.",
      "implementation": {
        "fields": [],
        "note": "Converts GPX track geometry and elevation. GPX timestamps and extensions are not preserved.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/gpx-to-kml/run",
      "api": {
        "id": "gpx-to-kml",
        "name": "GPX to KML",
        "category": "geo-tools",
        "description": "Convert GPX track geometry and elevation to KML.",
        "notes": "Converts GPX track geometry and elevation. GPX timestamps and extensions are not preserved.",
        "human_path": "/en/geo-tools/gpx-to-kml/",
        "method": "POST",
        "endpoint": "/api/v1/tools/gpx-to-kml/run",
        "schema_url": "/api/v1/tools/gpx-to-kml",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/geo-tools/gpx-to-kml/",
      "agent_url": "https://happytails.ai/agents/en/geo-tools/gpx-to-kml/"
    },
    {
      "id": "kml-to-geojson",
      "category": "geo-tools",
      "built": true,
      "requirements": "Geometry/CRS validation; explain unsupported KML styles and overlays.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/kml-to-geojson/run",
      "api": {
        "id": "kml-to-geojson",
        "name": "KML to geojson",
        "category": "geo-tools",
        "description": "Convert KML features to GeoJSON.",
        "notes": "",
        "human_path": "/en/geo-tools/kml-to-geojson/",
        "method": "POST",
        "endpoint": "/api/v1/tools/kml-to-geojson/run",
        "schema_url": "/api/v1/tools/kml-to-geojson",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/geo-tools/kml-to-geojson/",
      "agent_url": "https://happytails.ai/agents/en/geo-tools/kml-to-geojson/"
    },
    {
      "id": "add-image-border",
      "category": "image-tools",
      "built": true,
      "requirements": "Choose color and width in pixels; expand the canvas evenly; retain transparency inside.",
      "implementation": {
        "fields": [
          {
            "key": "border",
            "label": "Border width (px)",
            "value": 12,
            "type": "number",
            "min": 0,
            "max": 1000,
            "step": 1
          },
          {
            "key": "color",
            "label": "Border color",
            "value": "#ffffff",
            "type": "color"
          }
        ],
        "files": true,
        "input": false,
        "live": true,
        "liveFiles": true,
        "accept": ".png,.jpg,.jpeg,.webp",
        "maxFileBytes": 20971520,
        "note": "Runs on your device. Select an image for an automatic preview; settings update the result. Animated WebP produces one still frame.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/add-image-border/run",
      "api": {
        "id": "add-image-border",
        "name": "Add image border",
        "category": "image-tools",
        "description": "Add a solid border without covering your image.",
        "notes": "Runs on your device. Select an image for an automatic preview; settings update the result. Animated WebP produces one still frame.",
        "human_path": "/en/image-tools/add-image-border/",
        "method": "POST",
        "endpoint": "/api/v1/tools/add-image-border/run",
        "schema_url": "/api/v1/tools/add-image-border",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "border": {
                  "type": "number",
                  "description": "Border width (px)",
                  "default": 12.0,
                  "minimum": 0,
                  "maximum": 1000,
                  "multipleOf": 1
                },
                "color": {
                  "type": "string",
                  "description": "Border color",
                  "default": "#ffffff"
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/add-image-border/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/add-image-border/"
    },
    {
      "id": "adjust-brightness",
      "category": "image-tools",
      "built": true,
      "requirements": "Brightness and contrast controls; clipping preview and original comparison.",
      "implementation": {
        "fields": [
          {
            "key": "brightness",
            "label": "Brightness (%)",
            "value": 100,
            "type": "number"
          },
          {
            "key": "contrast",
            "label": "Contrast (%)",
            "value": 100,
            "type": "number"
          }
        ],
        "files": true,
        "accept": "image/*,.svg,.avif",
        "input": false,
        "note": "Runs in your browser. Animated inputs produce a single still image. Supported decoding depends on your browser.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/adjust-brightness/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/adjust-brightness/"
    },
    {
      "id": "adjust-image-contrast",
      "category": "image-tools",
      "built": true,
      "requirements": "Contrast 0 to 200 percent; 100 is unchanged; retain alpha and dimensions.",
      "implementation": {
        "fields": [
          {
            "key": "amount",
            "label": "Contrast (%)",
            "value": 120,
            "type": "number",
            "min": 0,
            "max": 200,
            "step": 1
          }
        ],
        "files": true,
        "input": false,
        "live": true,
        "liveFiles": true,
        "accept": ".png,.jpg,.jpeg,.webp",
        "maxFileBytes": 20971520,
        "note": "Runs on your device. Select an image for an automatic preview; settings update the result. Animated WebP produces one still frame.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/adjust-image-contrast/run",
      "api": {
        "id": "adjust-image-contrast",
        "name": "Adjust image contrast",
        "category": "image-tools",
        "description": "Adjust the contrast between light and dark areas.",
        "notes": "Runs on your device. Select an image for an automatic preview; settings update the result. Animated WebP produces one still frame.",
        "human_path": "/en/image-tools/adjust-image-contrast/",
        "method": "POST",
        "endpoint": "/api/v1/tools/adjust-image-contrast/run",
        "schema_url": "/api/v1/tools/adjust-image-contrast",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "amount": {
                  "type": "number",
                  "description": "Contrast (%)",
                  "default": 120.0,
                  "minimum": 0,
                  "maximum": 200,
                  "multipleOf": 1
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/adjust-image-contrast/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/adjust-image-contrast/"
    },
    {
      "id": "adjust-image-saturation",
      "category": "image-tools",
      "built": true,
      "requirements": "Saturation 0 to 200 percent; 100 is unchanged; retain alpha and dimensions.",
      "implementation": {
        "fields": [
          {
            "key": "amount",
            "label": "Saturation (%)",
            "value": 140,
            "type": "number",
            "min": 0,
            "max": 200,
            "step": 1
          }
        ],
        "files": true,
        "input": false,
        "live": true,
        "liveFiles": true,
        "accept": ".png,.jpg,.jpeg,.webp",
        "maxFileBytes": 20971520,
        "note": "Runs on your device. Select an image for an automatic preview; settings update the result. Animated WebP produces one still frame.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/adjust-image-saturation/run",
      "api": {
        "id": "adjust-image-saturation",
        "name": "Adjust image saturation",
        "category": "image-tools",
        "description": "Make colors more vivid or turn them down.",
        "notes": "Runs on your device. Select an image for an automatic preview; settings update the result. Animated WebP produces one still frame.",
        "human_path": "/en/image-tools/adjust-image-saturation/",
        "method": "POST",
        "endpoint": "/api/v1/tools/adjust-image-saturation/run",
        "schema_url": "/api/v1/tools/adjust-image-saturation",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "amount": {
                  "type": "number",
                  "description": "Saturation (%)",
                  "default": 140.0,
                  "minimum": 0,
                  "maximum": 200,
                  "multipleOf": 1
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/adjust-image-saturation/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/adjust-image-saturation/"
    },
    {
      "id": "ai-image-generator",
      "category": "image-tools",
      "built": true,
      "requirements": "Generate images from text with explicit size and queue limits; preserve prompts and model attribution; provide failure and content controls; measure GPU cost before offering a free quota.",
      "implementation": {
        "fields": [
          {
            "key": "seed",
            "label": "Seed (repeat a result)",
            "type": "number",
            "value": 42,
            "min": 0,
            "max": 2147483647,
            "step": 1
          },
          {
            "key": "steps",
            "label": "Detail steps",
            "type": "select",
            "value": "20",
            "values": [
              "12",
              "20",
              "30"
            ]
          }
        ],
        "files": false,
        "accept": "",
        "multiple": false,
        "input": true,
        "processing": "Server required",
        "native": true,
        "ai": false,
        "maxFileBytes": 20971520,
        "note": "Generate a 512 × 512 image using a local Tiny SD model on this server. No external image service. Usually takes several seconds or longer. Describe the subject, setting and style; generated text and fine details may be inaccurate.",
        "extra": true,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Generate image"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/ai-image-generator/run",
      "api": {
        "id": "ai-image-generator",
        "name": "AI image generator",
        "category": "image-tools",
        "description": "Generate a 512 × 512 image using a local Tiny SD model on this server.",
        "notes": "Generate a 512 × 512 image using a local Tiny SD model on this server. No external image service. Usually takes several seconds or longer. Describe the subject, setting and style; generated text and fine details may be inaccurate.",
        "human_path": "/en/image-tools/ai-image-generator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/ai-image-generator/run",
        "schema_url": "/api/v1/tools/ai-image-generator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "seed": {
                  "type": "number",
                  "description": "Seed (repeat a result)",
                  "default": 42.0,
                  "minimum": 0,
                  "maximum": 2147483647,
                  "multipleOf": 1
                },
                "steps": {
                  "type": "string",
                  "description": "Detail steps",
                  "default": "20",
                  "enum": [
                    "12",
                    "20",
                    "30"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 0,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/ai-image-generator/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/ai-image-generator/"
    },
    {
      "id": "apng-to-gif",
      "category": "image-tools",
      "built": true,
      "requirements": "Frame timing and palette tradeoffs; animated input fixture tests.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".webp,.png,.apng",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Processed by the local, self-hosted engine. No third-party conversion service is used. Preserves decoded animation frames and timing. GIF has fewer colours and only binary transparency.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/apng-to-gif/run",
      "api": {
        "id": "apng-to-gif",
        "name": "Apng to GIF",
        "category": "image-tools",
        "description": "Convert APNG files to GIF with the available format settings.",
        "notes": "Processed by the local, self-hosted engine. No third-party conversion service is used. Preserves decoded animation frames and timing. GIF has fewer colours and only binary transparency.",
        "human_path": "/en/image-tools/apng-to-gif/",
        "method": "POST",
        "endpoint": "/api/v1/tools/apng-to-gif/run",
        "schema_url": "/api/v1/tools/apng-to-gif",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/apng-to-gif/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/apng-to-gif/"
    },
    {
      "id": "avif-to-jpg",
      "category": "image-tools",
      "built": true,
      "requirements": "Flatten alpha against a chosen background; preview lossy quality and color changes.",
      "implementation": {
        "fields": [
          {
            "key": "background",
            "label": "JPEG background",
            "value": "#ffffff",
            "type": "color"
          }
        ],
        "files": true,
        "accept": ".avif",
        "input": false,
        "note": "Runs in your browser. Animated inputs produce a single still image. Supported decoding depends on your browser.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/avif-to-jpg/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/avif-to-jpg/"
    },
    {
      "id": "avif-to-png",
      "category": "image-tools",
      "built": true,
      "requirements": "Retain transparency where supported; explain larger output and HDR/color limitations.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".avif",
        "input": false,
        "note": "Runs in your browser. Animated inputs produce a single still image. Supported decoding depends on your browser.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/avif-to-png/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/avif-to-png/"
    },
    {
      "id": "base64-to-image",
      "category": "image-tools",
      "built": true,
      "requirements": "Validate data URI and actual image signature; preview safe formats with file-size limits.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/base64-to-image/run",
      "api": {
        "id": "base64-to-image",
        "name": "Base64 to image",
        "category": "image-tools",
        "description": "Validate data URI and actual image signature.",
        "notes": "",
        "human_path": "/en/image-tools/base64-to-image/",
        "method": "POST",
        "endpoint": "/api/v1/tools/base64-to-image/run",
        "schema_url": "/api/v1/tools/base64-to-image",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/base64-to-image/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/base64-to-image/"
    },
    {
      "id": "blur-image",
      "category": "image-tools",
      "built": true,
      "requirements": "Brush/rectangle blur with preview; explain that blur strength determines obscurity.",
      "implementation": {
        "fields": [
          {
            "key": "blur",
            "label": "Blur radius",
            "value": 8,
            "type": "number",
            "min": 1,
            "max": 100,
            "step": 1
          }
        ],
        "files": true,
        "accept": "image/*,.svg,.avif",
        "input": false,
        "note": "Runs in your browser. Animated inputs produce a single still image. Supported decoding depends on your browser.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/blur-image/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/blur-image/"
    },
    {
      "id": "bulk-resize-images",
      "category": "image-tools",
      "built": true,
      "requirements": "Up to 20 images and 20 MiB total; preserve aspect ratio; shrink only by default; report each output size; unique numbered filenames.",
      "implementation": {
        "fields": [
          {
            "key": "width",
            "label": "Maximum width (px)",
            "value": 1200,
            "type": "number",
            "min": 1,
            "max": 8192,
            "step": 1
          },
          {
            "key": "enlarge",
            "label": "Allow enlarging smaller images",
            "value": false,
            "type": "checkbox"
          }
        ],
        "files": true,
        "multiple": true,
        "input": false,
        "accept": ".png,.jpg,.jpeg,.webp",
        "maxFileBytes": 20971520,
        "note": "Runs on your device. Select up to 20 images. Aspect ratios and transparency are preserved. PNG output can be larger than a JPEG original.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/bulk-resize-images/run",
      "api": {
        "id": "bulk-resize-images",
        "name": "Bulk resize images",
        "category": "image-tools",
        "description": "Resize a batch of photos and download one ZIP.",
        "notes": "Runs on your device. Select up to 20 images. Aspect ratios and transparency are preserved. PNG output can be larger than a JPEG original.",
        "human_path": "/en/image-tools/bulk-resize-images/",
        "method": "POST",
        "endpoint": "/api/v1/tools/bulk-resize-images/run",
        "schema_url": "/api/v1/tools/bulk-resize-images",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "width": {
                  "type": "number",
                  "description": "Maximum width (px)",
                  "default": 1200.0,
                  "minimum": 1,
                  "maximum": 8192,
                  "multipleOf": 1
                },
                "enlarge": {
                  "type": "boolean",
                  "description": "Allow enlarging smaller images",
                  "default": false
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 20,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 20,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/bulk-resize-images/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/bulk-resize-images/"
    },
    {
      "id": "circle-crop-image",
      "category": "image-tools",
      "built": true,
      "requirements": "Center crop to the shorter side; transparent corners; preserve orientation and source file.",
      "implementation": {
        "fields": [],
        "files": true,
        "input": false,
        "live": true,
        "liveFiles": true,
        "accept": ".png,.jpg,.jpeg,.webp",
        "maxFileBytes": 20971520,
        "note": "Runs on your device. Select an image for an automatic preview; settings update the result. Animated WebP produces one still frame.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/circle-crop-image/run",
      "api": {
        "id": "circle-crop-image",
        "name": "Circle crop image",
        "category": "image-tools",
        "description": "Crop a centered circle and download a transparent PNG.",
        "notes": "Runs on your device. Select an image for an automatic preview; settings update the result. Animated WebP produces one still frame.",
        "human_path": "/en/image-tools/circle-crop-image/",
        "method": "POST",
        "endpoint": "/api/v1/tools/circle-crop-image/run",
        "schema_url": "/api/v1/tools/circle-crop-image",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/circle-crop-image/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/circle-crop-image/"
    },
    {
      "id": "compress-gif",
      "category": "image-tools",
      "built": true,
      "requirements": "Optimize frames/palette; show quality and frame-loss effects.",
      "implementation": {
        "fields": [
          {
            "key": "colors",
            "label": "Palette colours",
            "value": "64",
            "type": "select",
            "values": [
              "32",
              "64",
              "128",
              "256"
            ]
          }
        ],
        "files": true,
        "accept": ".gif",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Processed by the local, self-hosted engine. No third-party conversion service is used. Reduces the palette and optimises frames. Timing is preserved. Some already optimised files may become larger.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/compress-gif/run",
      "api": {
        "id": "compress-gif",
        "name": "Compress GIF",
        "category": "image-tools",
        "description": "Reduce an animated GIF’s colour palette while preserving frame timing.",
        "notes": "Processed by the local, self-hosted engine. No third-party conversion service is used. Reduces the palette and optimises frames. Timing is preserved. Some already optimised files may become larger.",
        "human_path": "/en/image-tools/compress-gif/",
        "method": "POST",
        "endpoint": "/api/v1/tools/compress-gif/run",
        "schema_url": "/api/v1/tools/compress-gif",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "colors": {
                  "type": "string",
                  "description": "Palette colours",
                  "default": "64",
                  "enum": [
                    "32",
                    "64",
                    "128",
                    "256"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/compress-gif/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/compress-gif/"
    },
    {
      "id": "compress-image",
      "category": "image-tools",
      "built": true,
      "requirements": "Show before/after bytes and preview; preserve original download; never guarantee all files shrink.",
      "implementation": {
        "fields": [
          {
            "key": "quality",
            "label": "Quality (%)",
            "value": 85,
            "type": "number",
            "min": 1,
            "max": 100,
            "step": 1
          },
          {
            "key": "format",
            "label": "Output format",
            "value": "WebP",
            "type": "select",
            "values": [
              "WebP",
              "JPEG"
            ]
          },
          {
            "key": "background",
            "label": "JPEG background",
            "value": "#ffffff",
            "type": "color"
          }
        ],
        "files": true,
        "accept": "image/*,.svg,.avif",
        "input": false,
        "note": "Runs in your browser. Animated inputs produce a single still image. Supported decoding depends on your browser.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Compress image"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/compress-image/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/compress-image/"
    },
    {
      "id": "compress-image-to-100kb",
      "category": "image-tools",
      "built": true,
      "requirements": "Actually target byte limit with resize/quality controls; report failure instead of lying about size.",
      "implementation": {
        "fields": [
          {
            "key": "format",
            "label": "Output format",
            "value": "WebP",
            "type": "select",
            "values": [
              "WebP",
              "JPEG"
            ]
          },
          {
            "key": "background",
            "label": "JPEG background",
            "value": "#ffffff",
            "type": "color"
          }
        ],
        "files": true,
        "accept": "image/*,.svg,.avif",
        "input": false,
        "note": "Runs in your browser. Animated inputs produce a single still image. Supported decoding depends on your browser.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Compress image"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/compress-image-to-100kb/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/compress-image-to-100kb/"
    },
    {
      "id": "crop-image",
      "category": "image-tools",
      "built": true,
      "requirements": "Visual crop, fixed aspect presets and pixel coordinates; export at intended resolution.",
      "implementation": {
        "fields": [
          {
            "key": "width",
            "label": "Width (px)",
            "value": "",
            "type": "number",
            "min": 1,
            "max": 16384,
            "step": 1
          },
          {
            "key": "height",
            "label": "Height (px)",
            "value": "",
            "type": "number",
            "min": 1,
            "max": 16384,
            "step": 1
          },
          {
            "key": "x",
            "label": "Left (px)",
            "value": 0,
            "type": "number",
            "min": 0,
            "step": 1
          },
          {
            "key": "y",
            "label": "Top (px)",
            "value": 0,
            "type": "number",
            "min": 0,
            "step": 1
          }
        ],
        "files": true,
        "accept": "image/*,.svg,.avif",
        "input": false,
        "note": "Runs in your browser. Animated inputs produce a single still image. Supported decoding depends on your browser.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/crop-image/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/crop-image/"
    },
    {
      "id": "dpi-converter",
      "category": "image-tools",
      "built": true,
      "requirements": "Change print-resolution metadata; clearly distinguish DPI from adding pixels.",
      "implementation": {
        "fields": [
          {
            "key": "dpi",
            "label": "Print DPI",
            "value": 300,
            "type": "number"
          }
        ],
        "files": true,
        "input": false,
        "accept": ".png",
        "note": "Edits PNG physical-resolution metadata only; it does not resize pixels or add image detail.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/dpi-converter/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/dpi-converter/"
    },
    {
      "id": "extract-gif-frames",
      "category": "image-tools",
      "built": true,
      "requirements": "Choose composited frames versus raw patches; numbered images and ZIP output.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".gif",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Processed by the local, self-hosted engine. No third-party conversion service is used. Exports full composited PNG frames plus timing.json inside a ZIP.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/extract-gif-frames/run",
      "api": {
        "id": "extract-gif-frames",
        "name": "Extract GIF frames",
        "category": "image-tools",
        "description": "Download a GIF’s frames and timing information as a ZIP.",
        "notes": "Processed by the local, self-hosted engine. No third-party conversion service is used. Exports full composited PNG frames plus timing.json inside a ZIP.",
        "human_path": "/en/image-tools/extract-gif-frames/",
        "method": "POST",
        "endpoint": "/api/v1/tools/extract-gif-frames/run",
        "schema_url": "/api/v1/tools/extract-gif-frames",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/extract-gif-frames/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/extract-gif-frames/"
    },
    {
      "id": "flip-image",
      "category": "image-tools",
      "built": true,
      "requirements": "Mirror pixels on the chosen axis without changing dimensions or transparency.",
      "implementation": {
        "fields": [
          {
            "key": "axis",
            "label": "Flip direction",
            "value": "Horizontal",
            "type": "select",
            "values": [
              "Horizontal",
              "Vertical"
            ]
          }
        ],
        "files": true,
        "input": false,
        "live": true,
        "liveFiles": true,
        "accept": ".png,.jpg,.jpeg,.webp",
        "maxFileBytes": 20971520,
        "note": "Runs on your device. Select an image for an automatic preview; settings update the result. Animated WebP produces one still frame.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/flip-image/run",
      "api": {
        "id": "flip-image",
        "name": "Flip image",
        "category": "image-tools",
        "description": "Flip an image horizontally or vertically.",
        "notes": "Runs on your device. Select an image for an automatic preview; settings update the result. Animated WebP produces one still frame.",
        "human_path": "/en/image-tools/flip-image/",
        "method": "POST",
        "endpoint": "/api/v1/tools/flip-image/run",
        "schema_url": "/api/v1/tools/flip-image",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "axis": {
                  "type": "string",
                  "description": "Flip direction",
                  "default": "Horizontal",
                  "enum": [
                    "Horizontal",
                    "Vertical"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/flip-image/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/flip-image/"
    },
    {
      "id": "gif-maker",
      "category": "image-tools",
      "built": true,
      "requirements": "Order frames, duration, loop count and palette; size preview.",
      "implementation": {
        "fields": [
          {
            "key": "duration",
            "label": "Frame duration (milliseconds)",
            "value": 200,
            "type": "number",
            "min": 20,
            "max": 10000,
            "step": 1
          },
          {
            "key": "loop",
            "label": "Loop count (0 repeats forever)",
            "value": 0,
            "type": "number",
            "min": 0,
            "max": 1000,
            "step": 1
          }
        ],
        "files": true,
        "accept": ".png,.jpg,.jpeg,.webp",
        "multiple": true,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Processed by the local, self-hosted engine. No third-party conversion service is used. ",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/gif-maker/run",
      "api": {
        "id": "gif-maker",
        "name": "GIF maker",
        "category": "image-tools",
        "description": "Combine matching-size images into an animated GIF.",
        "notes": "Processed by the local, self-hosted engine. No third-party conversion service is used. ",
        "human_path": "/en/image-tools/gif-maker/",
        "method": "POST",
        "endpoint": "/api/v1/tools/gif-maker/run",
        "schema_url": "/api/v1/tools/gif-maker",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "duration": {
                  "type": "number",
                  "description": "Frame duration (milliseconds)",
                  "default": 200.0,
                  "minimum": 20,
                  "maximum": 10000,
                  "multipleOf": 1
                },
                "loop": {
                  "type": "number",
                  "description": "Loop count (0 repeats forever)",
                  "default": 0.0,
                  "minimum": 0,
                  "maximum": 1000,
                  "multipleOf": 1
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 20,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 20,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/gif-maker/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/gif-maker/"
    },
    {
      "id": "gif-to-mp4",
      "category": "image-tools",
      "built": true,
      "requirements": "Choose loop duration/background and explain lack of original audio.",
      "implementation": {
        "fields": [
          {
            "key": "engine",
            "label": "Processing location",
            "type": "select",
            "value": "browser",
            "values": [
              "browser",
              "server"
            ],
            "labels": {
              "browser": "Browser (files stay here)",
              "server": "Local server (larger files)"
            }
          }
        ],
        "files": true,
        "accept": ".gif",
        "multiple": false,
        "input": false,
        "processing": "Browser or server",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Converts one animation cycle to silent H.264 video.",
        "hybrid": true,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/gif-to-mp4/run",
      "api": {
        "id": "gif-to-mp4",
        "name": "GIF to MP4",
        "category": "image-tools",
        "description": "Convert GIF files to MP4 with the available format settings.",
        "notes": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Converts one animation cycle to silent H.264 video.",
        "human_path": "/en/image-tools/gif-to-mp4/",
        "method": "POST",
        "endpoint": "/api/v1/tools/gif-to-mp4/run",
        "schema_url": "/api/v1/tools/gif-to-mp4",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "engine": {
                  "type": "string",
                  "description": "Processing location",
                  "default": "browser",
                  "enum": [
                    "browser",
                    "server"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/gif-to-mp4/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/gif-to-mp4/"
    },
    {
      "id": "grayscale-image",
      "category": "image-tools",
      "built": true,
      "requirements": "Grayscale conversion with export preview; preserve dimensions.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": "image/*,.svg,.avif",
        "input": false,
        "note": "Runs in your browser. Animated inputs produce a single still image. Supported decoding depends on your browser.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/grayscale-image/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/grayscale-image/"
    },
    {
      "id": "heic-to-jpg",
      "category": "image-tools",
      "built": true,
      "requirements": "Test orientation, color, multi-image HEIC and supported variants; show batch output naming.",
      "implementation": {
        "fields": [
          {
            "key": "quality",
            "label": "Quality (%)",
            "value": 85,
            "type": "number",
            "min": 1,
            "max": 100,
            "step": 1
          }
        ],
        "files": true,
        "accept": ".heic,.heif",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Processed by the local, self-hosted engine. No third-party conversion service is used. Converts the primary HEIC image with orientation applied. Multi-image sequences and HDR preservation are not supported.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/heic-to-jpg/run",
      "api": {
        "id": "heic-to-jpg",
        "name": "HEIC to JPG",
        "category": "image-tools",
        "description": "Convert HEIC files to JPG with the available format settings.",
        "notes": "Processed by the local, self-hosted engine. No third-party conversion service is used. Converts the primary HEIC image with orientation applied. Multi-image sequences and HDR preservation are not supported.",
        "human_path": "/en/image-tools/heic-to-jpg/",
        "method": "POST",
        "endpoint": "/api/v1/tools/heic-to-jpg/run",
        "schema_url": "/api/v1/tools/heic-to-jpg",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "quality": {
                  "type": "number",
                  "description": "Quality (%)",
                  "default": 85.0,
                  "minimum": 1,
                  "maximum": 100,
                  "multipleOf": 1
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/heic-to-jpg/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/heic-to-jpg/"
    },
    {
      "id": "heic-to-png",
      "category": "image-tools",
      "built": true,
      "requirements": "Verify HEIC decode and orientation; explain PNG size and unsupported HDR features.",
      "implementation": {
        "fields": [
          {
            "key": "quality",
            "label": "Quality (%)",
            "value": 85,
            "type": "number",
            "min": 1,
            "max": 100,
            "step": 1
          }
        ],
        "files": true,
        "accept": ".heic,.heif",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Processed by the local, self-hosted engine. No third-party conversion service is used. Converts the primary HEIC image with orientation applied. Multi-image sequences and HDR preservation are not supported.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/heic-to-png/run",
      "api": {
        "id": "heic-to-png",
        "name": "HEIC to PNG",
        "category": "image-tools",
        "description": "Convert HEIC files to PNG with the available format settings.",
        "notes": "Processed by the local, self-hosted engine. No third-party conversion service is used. Converts the primary HEIC image with orientation applied. Multi-image sequences and HDR preservation are not supported.",
        "human_path": "/en/image-tools/heic-to-png/",
        "method": "POST",
        "endpoint": "/api/v1/tools/heic-to-png/run",
        "schema_url": "/api/v1/tools/heic-to-png",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "quality": {
                  "type": "number",
                  "description": "Quality (%)",
                  "default": 85.0,
                  "minimum": 1,
                  "maximum": 100,
                  "multipleOf": 1
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/heic-to-png/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/heic-to-png/"
    },
    {
      "id": "html-to-image",
      "category": "image-tools",
      "built": true,
      "requirements": "Isolated rendering, viewport selection and remote-resource limits.",
      "implementation": {
        "fields": [
          {
            "key": "width",
            "label": "Image width (pixels)",
            "value": 800,
            "type": "number",
            "min": 100,
            "max": 1920,
            "step": 1
          },
          {
            "key": "height",
            "label": "Image height (pixels)",
            "value": 600,
            "type": "number",
            "min": 100,
            "max": 2000,
            "step": 1
          }
        ],
        "note": "Render simple HTML as a PNG entirely in your browser. Scripts, supplied CSS, images, and external resources are stripped. This is not a website screenshot tool.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "HTML source",
          "placeholder": "<p>Hello <strong>world</strong>.</p>",
          "help": "Paste HTML markup, not a website URL. Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/html-to-image/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/html-to-image/"
    },
    {
      "id": "image-to-base64",
      "category": "image-tools",
      "built": true,
      "requirements": "Data-URI versus raw Base64 output; warn about size expansion; support copy and text download.",
      "implementation": {
        "fields": [],
        "files": true,
        "input": false,
        "accept": ".png,.jpg,.jpeg,.webp,.gif,.avif",
        "note": "Encodes PNG, JPEG, WebP, GIF, or AVIF bytes as an image data URL. The image format is detected from its contents.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/image-to-base64/run",
      "api": {
        "id": "image-to-base64",
        "name": "Image to base64",
        "category": "image-tools",
        "description": "Data-URI versus raw Base64 output.",
        "notes": "Encodes PNG, JPEG, WebP, GIF, or AVIF bytes as an image data URL. The image format is detected from its contents.",
        "human_path": "/en/image-tools/image-to-base64/",
        "method": "POST",
        "endpoint": "/api/v1/tools/image-to-base64/run",
        "schema_url": "/api/v1/tools/image-to-base64",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/image-to-base64/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/image-to-base64/"
    },
    {
      "id": "image-to-text",
      "category": "image-tools",
      "built": true,
      "requirements": "Local or disclosed remote OCR; language packs, layout and error review.",
      "implementation": {
        "fields": [
          {
            "key": "language",
            "label": "OCR language",
            "value": "eng",
            "type": "select",
            "values": [
              "eng"
            ]
          }
        ],
        "files": true,
        "accept": ".png,.jpg,.jpeg,.webp,.tif,.tiff",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Processed by the local, self-hosted engine. No third-party conversion service is used. Local Tesseract OCR. English is installed. Check recognised text for errors.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/image-to-text/run",
      "api": {
        "id": "image-to-text",
        "name": "Image to text",
        "category": "image-tools",
        "description": "Read text from an image using local OCR.",
        "notes": "Processed by the local, self-hosted engine. No third-party conversion service is used. Local Tesseract OCR. English is installed. Check recognised text for errors.",
        "human_path": "/en/image-tools/image-to-text/",
        "method": "POST",
        "endpoint": "/api/v1/tools/image-to-text/run",
        "schema_url": "/api/v1/tools/image-to-text",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "language": {
                  "type": "string",
                  "description": "OCR language",
                  "default": "eng",
                  "enum": [
                    "eng"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/image-to-text/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/image-to-text/"
    },
    {
      "id": "invert-image",
      "category": "image-tools",
      "built": true,
      "requirements": "Invert RGB while preserving alpha; preview and compare with original.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": "image/*,.svg,.avif",
        "input": false,
        "note": "Runs in your browser. Animated inputs produce a single still image. Supported decoding depends on your browser.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/invert-image/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/invert-image/"
    },
    {
      "id": "jpg-to-avif",
      "category": "image-tools",
      "built": true,
      "requirements": "Codec quality/speed controls with tested AVIF output compatibility.",
      "implementation": {
        "fields": [
          {
            "key": "quality",
            "label": "Quality (%)",
            "value": 85,
            "type": "number",
            "min": 1,
            "max": 100,
            "step": 1
          }
        ],
        "files": true,
        "accept": ".jpg,.jpeg",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Processed by the local, self-hosted engine. No third-party conversion service is used. ",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/jpg-to-avif/run",
      "api": {
        "id": "jpg-to-avif",
        "name": "JPG to AVIF",
        "category": "image-tools",
        "description": "Convert JPG files to AVIF with the available format settings.",
        "notes": "Processed by the local, self-hosted engine. No third-party conversion service is used. ",
        "human_path": "/en/image-tools/jpg-to-avif/",
        "method": "POST",
        "endpoint": "/api/v1/tools/jpg-to-avif/run",
        "schema_url": "/api/v1/tools/jpg-to-avif",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "quality": {
                  "type": "number",
                  "description": "Quality (%)",
                  "default": 85.0,
                  "minimum": 1,
                  "maximum": 100,
                  "multipleOf": 1
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/jpg-to-avif/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/jpg-to-avif/"
    },
    {
      "id": "jpg-to-png",
      "category": "image-tools",
      "built": true,
      "requirements": "Explain that PNG cannot restore lost JPEG detail or create a transparent background.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".jpg,.jpeg",
        "input": false,
        "note": "Runs in your browser. Animated inputs produce a single still image. Supported decoding depends on your browser.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/jpg-to-png/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/jpg-to-png/"
    },
    {
      "id": "jpg-to-webp",
      "category": "image-tools",
      "built": true,
      "requirements": "Compare quality and bytes; preserve dimensions; expose supported encoding modes.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".jpg,.jpeg",
        "input": false,
        "note": "Runs in your browser. Animated inputs produce a single still image. Supported decoding depends on your browser.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/jpg-to-webp/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/jpg-to-webp/"
    },
    {
      "id": "meme-generator",
      "category": "image-tools",
      "built": true,
      "requirements": "User images, editable text and accessible font controls; no watermark.",
      "implementation": {
        "fields": [
          {
            "key": "caption",
            "label": "Caption / watermark",
            "value": "Happytails.ai",
            "type": "text"
          },
          {
            "key": "fontSize",
            "label": "Font size",
            "value": 36,
            "type": "number"
          },
          {
            "key": "color",
            "label": "Text color",
            "value": "#ffffff",
            "type": "color"
          }
        ],
        "files": true,
        "accept": "image/*,.svg,.avif",
        "input": false,
        "note": "Runs in your browser. Animated inputs produce a single still image. Supported decoding depends on your browser.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/meme-generator/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/meme-generator/"
    },
    {
      "id": "merge-images",
      "category": "image-tools",
      "built": true,
      "requirements": "Horizontal/vertical layout, spacing, background and equal-size options.",
      "implementation": {
        "fields": [
          {
            "key": "direction",
            "label": "Arrange",
            "value": "Horizontal",
            "type": "select",
            "values": [
              "Horizontal",
              "Vertical"
            ]
          },
          {
            "key": "background",
            "label": "Background",
            "value": "#ffffff",
            "type": "color"
          }
        ],
        "files": true,
        "multiple": true,
        "input": false,
        "accept": "image/*,.svg,.avif",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/merge-images/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/merge-images/"
    },
    {
      "id": "photo-denoiser",
      "category": "image-tools",
      "built": true,
      "requirements": "Reduce visual noise without resizing by default; compare crops and adjustable strength; avoid erasing text, skin texture and fine edges.",
      "implementation": {
        "fields": [
          {
            "key": "strength",
            "label": "Denoising strength",
            "value": 7,
            "type": "number",
            "min": 1,
            "max": 20,
            "step": "any"
          }
        ],
        "files": true,
        "accept": ".png,.jpg,.jpeg,.webp",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Processed by the local, self-hosted engine. No third-party conversion service is used. Classical OpenCV denoising at the original size. No generative model or invented detail.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/photo-denoiser/run",
      "api": {
        "id": "photo-denoiser",
        "name": "Photo denoiser",
        "category": "image-tools",
        "description": "Reduce colour noise in a photo with adjustable strength.",
        "notes": "Processed by the local, self-hosted engine. No third-party conversion service is used. Classical OpenCV denoising at the original size. No generative model or invented detail.",
        "human_path": "/en/image-tools/photo-denoiser/",
        "method": "POST",
        "endpoint": "/api/v1/tools/photo-denoiser/run",
        "schema_url": "/api/v1/tools/photo-denoiser",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "strength": {
                  "type": "number",
                  "description": "Denoising strength",
                  "default": 7.0,
                  "minimum": 1,
                  "maximum": 20
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/photo-denoiser/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/photo-denoiser/"
    },
    {
      "id": "photo-to-line-drawing",
      "category": "image-tools",
      "built": true,
      "requirements": "Create outlines using local edge detection with threshold, smoothing and line controls; compare original and result; export PNG, with SVG only after real vector tracing is implemented; validate portraits and noisy backgrounds without requiring generative AI.",
      "implementation": {
        "fields": [
          {
            "key": "threshold",
            "label": "Outline threshold",
            "value": 35,
            "type": "number"
          }
        ],
        "files": true,
        "accept": "image/*,.svg,.avif",
        "input": false,
        "note": "Runs in your browser. Animated inputs produce a single still image. Supported decoding depends on your browser.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/photo-to-line-drawing/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/photo-to-line-drawing/"
    },
    {
      "id": "pixelate-image",
      "category": "image-tools",
      "built": true,
      "requirements": "Block size in source pixels; preserve dimensions. This effect is not secure redaction.",
      "implementation": {
        "fields": [
          {
            "key": "block",
            "label": "Block size (px)",
            "value": 12,
            "type": "number",
            "min": 1,
            "max": 500,
            "step": 1
          }
        ],
        "files": true,
        "input": false,
        "live": true,
        "liveFiles": true,
        "accept": ".png,.jpg,.jpeg,.webp",
        "maxFileBytes": 20971520,
        "note": "Runs on your device. Select an image for an automatic preview; settings update the result. Animated WebP produces one still frame. Pixelation is an effect, not secure redaction.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/pixelate-image/run",
      "api": {
        "id": "pixelate-image",
        "name": "Pixelate image",
        "category": "image-tools",
        "description": "Turn an image into blocks of color.",
        "notes": "Runs on your device. Select an image for an automatic preview; settings update the result. Animated WebP produces one still frame. Pixelation is an effect, not secure redaction.",
        "human_path": "/en/image-tools/pixelate-image/",
        "method": "POST",
        "endpoint": "/api/v1/tools/pixelate-image/run",
        "schema_url": "/api/v1/tools/pixelate-image",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "block": {
                  "type": "number",
                  "description": "Block size (px)",
                  "default": 12.0,
                  "minimum": 1,
                  "maximum": 500,
                  "multipleOf": 1
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/pixelate-image/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/pixelate-image/"
    },
    {
      "id": "png-to-ico",
      "category": "image-tools",
      "built": true,
      "requirements": "Create real multi-resolution ICO; show pixel-size previews.",
      "implementation": {
        "fields": [
          {
            "key": "size",
            "label": "Icon size",
            "value": "32",
            "type": "select",
            "values": [
              "16",
              "32",
              "48",
              "64",
              "128",
              "256"
            ]
          }
        ],
        "files": true,
        "input": false,
        "accept": "image/*,.svg,.avif",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/png-to-ico/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/png-to-ico/"
    },
    {
      "id": "png-to-jpg",
      "category": "image-tools",
      "built": true,
      "requirements": "Flatten transparent pixels predictably; explain lossy JPEG and remove misleading quality claims.",
      "implementation": {
        "fields": [
          {
            "key": "background",
            "label": "JPEG background",
            "value": "#ffffff",
            "type": "color"
          }
        ],
        "files": true,
        "accept": ".png",
        "input": false,
        "note": "Runs in your browser. Animated inputs produce a single still image. Supported decoding depends on your browser.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/png-to-jpg/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/png-to-jpg/"
    },
    {
      "id": "png-to-svg",
      "category": "image-tools",
      "built": true,
      "requirements": "CPU vector tracing, not an embedded bitmap; bounded image size and color precision; preserve transparent background; compare rasterized output.",
      "implementation": {
        "fields": [
          {
            "key": "precision",
            "label": "Color precision (bits per channel)",
            "value": 6,
            "type": "number",
            "min": 1,
            "max": 8,
            "step": 1
          }
        ],
        "files": true,
        "accept": ".png",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "expansion": true,
        "maxFileBytes": 20971520,
        "note": "Processed on our server with no external conversion service. Traces colored shapes with VTracer on CPU. Best for logos and illustrations. Photos can produce large SVG files; use an image of at most 4 megapixels.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/png-to-svg/run",
      "api": {
        "id": "png-to-svg",
        "name": "PNG to SVG",
        "category": "image-tools",
        "description": "Trace a PNG into editable vector shapes.",
        "notes": "Processed on our server with no external conversion service. Traces colored shapes with VTracer on CPU. Best for logos and illustrations. Photos can produce large SVG files; use an image of at most 4 megapixels.",
        "human_path": "/en/image-tools/png-to-svg/",
        "method": "POST",
        "endpoint": "/api/v1/tools/png-to-svg/run",
        "schema_url": "/api/v1/tools/png-to-svg",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "precision": {
                  "type": "number",
                  "description": "Color precision (bits per channel)",
                  "default": 6.0,
                  "minimum": 1,
                  "maximum": 8,
                  "multipleOf": 1
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/png-to-svg/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/png-to-svg/"
    },
    {
      "id": "png-to-webp",
      "category": "image-tools",
      "built": true,
      "requirements": "Preserve alpha; expose lossy/lossless options only when engine supports them.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".png",
        "input": false,
        "note": "Runs in your browser. Animated inputs produce a single still image. Supported decoding depends on your browser.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/png-to-webp/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/png-to-webp/"
    },
    {
      "id": "product-photo-background",
      "category": "image-tools",
      "built": true,
      "requirements": "Cut out a product, refine edges, add a solid background and deterministic shadow; export common marketplace sizes. Generative backgrounds are a separate later mode.",
      "implementation": {
        "fields": [
          {
            "key": "background",
            "label": "Background colour",
            "value": "#ffffff",
            "type": "color"
          }
        ],
        "files": true,
        "accept": ".png,.jpg,.jpeg,.webp",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "extra": true,
        "maxFileBytes": 20971520,
        "note": "Processed locally on this website’s server without an external conversion API. Cuts out the foreground and adds a solid colour. Does not generate scenes or add artificial shadows.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/product-photo-background/run",
      "api": {
        "id": "product-photo-background",
        "name": "Product photo background",
        "category": "image-tools",
        "description": "Replace a product photo’s background with a solid colour.",
        "notes": "Processed locally on this website’s server without an external conversion API. Cuts out the foreground and adds a solid colour. Does not generate scenes or add artificial shadows.",
        "human_path": "/en/image-tools/product-photo-background/",
        "method": "POST",
        "endpoint": "/api/v1/tools/product-photo-background/run",
        "schema_url": "/api/v1/tools/product-photo-background",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "background": {
                  "type": "string",
                  "description": "Background colour",
                  "default": "#ffffff"
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/product-photo-background/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/product-photo-background/"
    },
    {
      "id": "remove-background",
      "category": "image-tools",
      "built": true,
      "requirements": "Quality-tested segmentation with edge correction; disclose model download or upload.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".png,.jpg,.jpeg,.webp",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "extra": true,
        "maxFileBytes": 20971520,
        "note": "Processed locally on this website’s server without an external conversion API. Uses the small U2Netp segmentation model. Fine hair, transparent objects, and difficult edges may need manual correction.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/remove-background/run",
      "api": {
        "id": "remove-background",
        "name": "Remove background",
        "category": "image-tools",
        "description": "Remove an image background and export a transparent PNG.",
        "notes": "Processed locally on this website’s server without an external conversion API. Uses the small U2Netp segmentation model. Fine hair, transparent objects, and difficult edges may need manual correction.",
        "human_path": "/en/image-tools/remove-background/",
        "method": "POST",
        "endpoint": "/api/v1/tools/remove-background/run",
        "schema_url": "/api/v1/tools/remove-background",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/remove-background/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/remove-background/"
    },
    {
      "id": "remove-metadata",
      "category": "image-tools",
      "built": true,
      "requirements": "Verify removal of GPS/EXIF fields per format; distinguish metadata removal from visual anonymization.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": "image/*,.svg,.avif",
        "input": false,
        "note": "Runs in your browser. Animated inputs produce a single still image. Supported decoding depends on your browser.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/remove-metadata/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/remove-metadata/"
    },
    {
      "id": "remove-object",
      "category": "image-tools",
      "built": true,
      "requirements": "Paint a mask and fill the selected area; retain undo and before-after comparison; report generated pixels; evaluate texture seams and unwanted scene changes.",
      "implementation": {
        "fields": [
          {
            "key": "x",
            "label": "Mask left (pixels)",
            "value": 10,
            "type": "number",
            "min": 0,
            "max": 16000,
            "step": 1
          },
          {
            "key": "y",
            "label": "Mask top (pixels)",
            "value": 10,
            "type": "number",
            "min": 0,
            "max": 16000,
            "step": 1
          },
          {
            "key": "width",
            "label": "Mask width (pixels)",
            "value": 30,
            "type": "number",
            "min": 1,
            "max": 4000,
            "step": 1
          },
          {
            "key": "height",
            "label": "Mask height (pixels)",
            "value": 30,
            "type": "number",
            "min": 1,
            "max": 4000,
            "step": 1
          }
        ],
        "files": true,
        "accept": ".png,.jpg,.jpeg,.webp",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Processed by the local, self-hosted engine. No third-party conversion service is used. Fills a rectangular region using nearby pixels (OpenCV inpainting). Best for small marks on simple backgrounds, not large generative edits.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/remove-object/run",
      "api": {
        "id": "remove-object",
        "name": "Remove object",
        "category": "image-tools",
        "description": "Fill a selected rectangular image area using nearby pixels.",
        "notes": "Processed by the local, self-hosted engine. No third-party conversion service is used. Fills a rectangular region using nearby pixels (OpenCV inpainting). Best for small marks on simple backgrounds, not large generative edits.",
        "human_path": "/en/image-tools/remove-object/",
        "method": "POST",
        "endpoint": "/api/v1/tools/remove-object/run",
        "schema_url": "/api/v1/tools/remove-object",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "x": {
                  "type": "number",
                  "description": "Mask left (pixels)",
                  "default": 10.0,
                  "minimum": 0,
                  "maximum": 16000,
                  "multipleOf": 1
                },
                "y": {
                  "type": "number",
                  "description": "Mask top (pixels)",
                  "default": 10.0,
                  "minimum": 0,
                  "maximum": 16000,
                  "multipleOf": 1
                },
                "width": {
                  "type": "number",
                  "description": "Mask width (pixels)",
                  "default": 30.0,
                  "minimum": 1,
                  "maximum": 4000,
                  "multipleOf": 1
                },
                "height": {
                  "type": "number",
                  "description": "Mask height (pixels)",
                  "default": 30.0,
                  "minimum": 1,
                  "maximum": 4000,
                  "multipleOf": 1
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/remove-object/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/remove-object/"
    },
    {
      "id": "resize-gif",
      "category": "image-tools",
      "built": true,
      "requirements": "Preserve animation timing and loop metadata while resizing frames.",
      "implementation": {
        "fields": [
          {
            "key": "width",
            "label": "Width (pixels)",
            "value": 480,
            "type": "number",
            "min": 16,
            "max": 1920,
            "step": 1
          }
        ],
        "files": true,
        "accept": ".gif",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Processed by the local, self-hosted engine. No third-party conversion service is used. ",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/resize-gif/run",
      "api": {
        "id": "resize-gif",
        "name": "Resize GIF",
        "category": "image-tools",
        "description": "Resize every GIF frame to your chosen width.",
        "notes": "Processed by the local, self-hosted engine. No third-party conversion service is used. ",
        "human_path": "/en/image-tools/resize-gif/",
        "method": "POST",
        "endpoint": "/api/v1/tools/resize-gif/run",
        "schema_url": "/api/v1/tools/resize-gif",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "width": {
                  "type": "number",
                  "description": "Width (pixels)",
                  "default": 480.0,
                  "minimum": 16,
                  "maximum": 1920,
                  "multipleOf": 1
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/resize-gif/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/resize-gif/"
    },
    {
      "id": "resize-image",
      "category": "image-tools",
      "built": true,
      "requirements": "Pixels/percent, aspect lock, fit/crop modes, no unintended upscaling, batch dimensions.",
      "implementation": {
        "fields": [
          {
            "key": "width",
            "label": "Width (px)",
            "value": "",
            "type": "number",
            "min": 1,
            "max": 16384,
            "step": 1
          },
          {
            "key": "height",
            "label": "Height (px)",
            "value": "",
            "type": "number",
            "min": 1,
            "max": 16384,
            "step": 1
          },
          {
            "key": "lock",
            "label": "Keep aspect ratio",
            "value": true,
            "type": "checkbox"
          }
        ],
        "files": true,
        "accept": "image/*,.svg,.avif",
        "input": false,
        "note": "Runs in your browser. Animated inputs produce a single still image. Supported decoding depends on your browser.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Resize image"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/resize-image/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/resize-image/"
    },
    {
      "id": "restore-old-photo",
      "category": "image-tools",
      "built": true,
      "requirements": "Combine scratch masking, denoising and optional restoration with independent controls; preserve original; never present invented facial detail as recovered fact.",
      "implementation": {
        "fields": [
          {
            "key": "strength",
            "label": "Denoising strength",
            "value": 7,
            "type": "number",
            "min": 1,
            "max": 20
          },
          {
            "key": "contrast",
            "label": "Improve tonal contrast",
            "value": true,
            "type": "checkbox"
          }
        ],
        "files": true,
        "accept": ".png,.jpg,.jpeg,.webp",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "extra": true,
        "maxFileBytes": 20971520,
        "note": "Processed locally on this website’s server without an external conversion API. Classical denoising and optional contrast correction. Does not reconstruct faces, colourise, or remove large scratches.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/restore-old-photo/run",
      "api": {
        "id": "restore-old-photo",
        "name": "Restore old photo",
        "category": "image-tools",
        "description": "Reduce noise and improve contrast in an old photo.",
        "notes": "Processed locally on this website’s server without an external conversion API. Classical denoising and optional contrast correction. Does not reconstruct faces, colourise, or remove large scratches.",
        "human_path": "/en/image-tools/restore-old-photo/",
        "method": "POST",
        "endpoint": "/api/v1/tools/restore-old-photo/run",
        "schema_url": "/api/v1/tools/restore-old-photo",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "strength": {
                  "type": "number",
                  "description": "Denoising strength",
                  "default": 7.0,
                  "minimum": 1,
                  "maximum": 20
                },
                "contrast": {
                  "type": "boolean",
                  "description": "Improve tonal contrast",
                  "default": true
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/restore-old-photo/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/restore-old-photo/"
    },
    {
      "id": "rotate-image",
      "category": "image-tools",
      "built": true,
      "requirements": "Rotate and mirror with explicit controls; explain re-encoding and orientation metadata.",
      "implementation": {
        "fields": [
          {
            "key": "angle",
            "label": "Rotation",
            "value": "0",
            "type": "select",
            "values": [
              "0",
              "90",
              "180",
              "270"
            ]
          },
          {
            "key": "flip",
            "label": "Mirror horizontally",
            "value": false,
            "type": "checkbox"
          }
        ],
        "files": true,
        "accept": "image/*,.svg,.avif",
        "input": false,
        "note": "Runs in your browser. Animated inputs produce a single still image. Supported decoding depends on your browser.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/rotate-image/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/rotate-image/"
    },
    {
      "id": "round-image-corners",
      "category": "image-tools",
      "built": true,
      "requirements": "Radius in source pixels, clamped to half the shorter side; retain source dimensions and alpha.",
      "implementation": {
        "fields": [
          {
            "key": "radius",
            "label": "Corner radius (px)",
            "value": 24,
            "type": "number",
            "min": 0,
            "max": 8192,
            "step": 1
          }
        ],
        "files": true,
        "input": false,
        "live": true,
        "liveFiles": true,
        "accept": ".png,.jpg,.jpeg,.webp",
        "maxFileBytes": 20971520,
        "note": "Runs on your device. Select an image for an automatic preview; settings update the result. Animated WebP produces one still frame.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/round-image-corners/run",
      "api": {
        "id": "round-image-corners",
        "name": "Round image corners",
        "category": "image-tools",
        "description": "Give an image rounded corners with a transparent background.",
        "notes": "Runs on your device. Select an image for an automatic preview; settings update the result. Animated WebP produces one still frame.",
        "human_path": "/en/image-tools/round-image-corners/",
        "method": "POST",
        "endpoint": "/api/v1/tools/round-image-corners/run",
        "schema_url": "/api/v1/tools/round-image-corners",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "radius": {
                  "type": "number",
                  "description": "Corner radius (px)",
                  "default": 24.0,
                  "minimum": 0,
                  "maximum": 8192,
                  "multipleOf": 1
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/round-image-corners/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/round-image-corners/"
    },
    {
      "id": "sepia-image",
      "category": "image-tools",
      "built": true,
      "requirements": "Adjust effect strength from 0 to 100 percent; preserve transparency and dimensions.",
      "implementation": {
        "fields": [
          {
            "key": "amount",
            "label": "Sepia strength (%)",
            "value": 100,
            "type": "number",
            "min": 0,
            "max": 100,
            "step": 1
          }
        ],
        "files": true,
        "input": false,
        "live": true,
        "liveFiles": true,
        "accept": ".png,.jpg,.jpeg,.webp",
        "maxFileBytes": 20971520,
        "note": "Runs on your device. Select an image for an automatic preview; settings update the result. Animated WebP produces one still frame.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/sepia-image/run",
      "api": {
        "id": "sepia-image",
        "name": "Sepia image",
        "category": "image-tools",
        "description": "Give your photo a warm sepia tint.",
        "notes": "Runs on your device. Select an image for an automatic preview; settings update the result. Animated WebP produces one still frame.",
        "human_path": "/en/image-tools/sepia-image/",
        "method": "POST",
        "endpoint": "/api/v1/tools/sepia-image/run",
        "schema_url": "/api/v1/tools/sepia-image",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "amount": {
                  "type": "number",
                  "description": "Sepia strength (%)",
                  "default": 100.0,
                  "minimum": 0,
                  "maximum": 100,
                  "multipleOf": 1
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/sepia-image/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/sepia-image/"
    },
    {
      "id": "sharpen-image",
      "category": "image-tools",
      "built": true,
      "requirements": "Bounded sharpening strength; preserve alpha and dimensions; cannot recover lost detail.",
      "implementation": {
        "fields": [
          {
            "key": "amount",
            "label": "Sharpening strength (%)",
            "value": 50,
            "type": "number",
            "min": 0,
            "max": 100,
            "step": 1
          }
        ],
        "files": true,
        "input": false,
        "live": true,
        "liveFiles": true,
        "accept": ".png,.jpg,.jpeg,.webp",
        "maxFileBytes": 20971520,
        "note": "Runs on your device. Select an image for an automatic preview; settings update the result. Animated WebP produces one still frame.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/sharpen-image/run",
      "api": {
        "id": "sharpen-image",
        "name": "Sharpen image",
        "category": "image-tools",
        "description": "Make edges clearer with adjustable sharpening.",
        "notes": "Runs on your device. Select an image for an automatic preview; settings update the result. Animated WebP produces one still frame.",
        "human_path": "/en/image-tools/sharpen-image/",
        "method": "POST",
        "endpoint": "/api/v1/tools/sharpen-image/run",
        "schema_url": "/api/v1/tools/sharpen-image",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "amount": {
                  "type": "number",
                  "description": "Sharpening strength (%)",
                  "default": 50.0,
                  "minimum": 0,
                  "maximum": 100,
                  "multipleOf": 1
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/sharpen-image/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/sharpen-image/"
    },
    {
      "id": "split-image",
      "category": "image-tools",
      "built": true,
      "requirements": "Grid or custom slices; pixel-accurate boundaries and ZIP export.",
      "implementation": {
        "fields": [
          {
            "key": "cols",
            "label": "Columns",
            "value": 2,
            "type": "number"
          },
          {
            "key": "rows",
            "label": "Rows",
            "value": 2,
            "type": "number"
          }
        ],
        "files": true,
        "input": false,
        "accept": "image/*,.svg,.avif",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/split-image/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/split-image/"
    },
    {
      "id": "svg-to-png",
      "category": "image-tools",
      "built": true,
      "requirements": "Choose pixel dimensions; reject or sanitize active content and remote references; test fonts.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".svg",
        "input": false,
        "note": "Runs in your browser. Animated inputs produce a single still image. Supported decoding depends on your browser.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/svg-to-png/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/svg-to-png/"
    },
    {
      "id": "threshold-image",
      "category": "image-tools",
      "built": true,
      "requirements": "Luminance threshold 0 to 255; preserve transparency; PNG output has only black or white RGB pixels.",
      "implementation": {
        "fields": [
          {
            "key": "threshold",
            "label": "Black / white threshold",
            "value": 128,
            "type": "number",
            "min": 0,
            "max": 255,
            "step": 1
          }
        ],
        "files": true,
        "input": false,
        "live": true,
        "liveFiles": true,
        "accept": ".png,.jpg,.jpeg,.webp",
        "maxFileBytes": 20971520,
        "note": "Runs on your device. Select an image for an automatic preview; settings update the result. Animated WebP produces one still frame.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/threshold-image/run",
      "api": {
        "id": "threshold-image",
        "name": "Threshold image",
        "category": "image-tools",
        "description": "Convert an image to pure black and white.",
        "notes": "Runs on your device. Select an image for an automatic preview; settings update the result. Animated WebP produces one still frame.",
        "human_path": "/en/image-tools/threshold-image/",
        "method": "POST",
        "endpoint": "/api/v1/tools/threshold-image/run",
        "schema_url": "/api/v1/tools/threshold-image",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "threshold": {
                  "type": "number",
                  "description": "Black / white threshold",
                  "default": 128.0,
                  "minimum": 0,
                  "maximum": 255,
                  "multipleOf": 1
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/threshold-image/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/threshold-image/"
    },
    {
      "id": "upscale-image",
      "category": "image-tools",
      "built": true,
      "requirements": "Compare interpolation and model-based enhancement; no invented detail guarantees.",
      "implementation": {
        "fields": [
          {
            "key": "scale",
            "label": "Scale factor",
            "value": "2",
            "type": "select",
            "values": [
              "2",
              "4"
            ]
          }
        ],
        "files": true,
        "accept": ".png,.jpg,.jpeg,.webp",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "extra": true,
        "maxFileBytes": 20971520,
        "note": "Processed locally on this website’s server without an external conversion API. High-quality Lanczos resampling. This version increases resolution without an AI model or invented detail.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/upscale-image/run",
      "api": {
        "id": "upscale-image",
        "name": "Upscale image",
        "category": "image-tools",
        "description": "Enlarge an image with high-quality Lanczos resampling.",
        "notes": "Processed locally on this website’s server without an external conversion API. High-quality Lanczos resampling. This version increases resolution without an AI model or invented detail.",
        "human_path": "/en/image-tools/upscale-image/",
        "method": "POST",
        "endpoint": "/api/v1/tools/upscale-image/run",
        "schema_url": "/api/v1/tools/upscale-image",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "scale": {
                  "type": "string",
                  "description": "Scale factor",
                  "default": "2",
                  "enum": [
                    "2",
                    "4"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/upscale-image/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/upscale-image/"
    },
    {
      "id": "video-to-gif",
      "category": "image-tools",
      "built": true,
      "requirements": "Select short range, frame rate and dimensions; warn about large outputs.",
      "implementation": {
        "fields": [
          {
            "key": "start",
            "label": "Start (seconds)",
            "value": 0,
            "type": "number",
            "min": 0,
            "max": 1800,
            "step": "any"
          },
          {
            "key": "duration",
            "label": "Duration (seconds)",
            "value": 3,
            "type": "number",
            "min": 0.1,
            "max": 15,
            "step": "any"
          },
          {
            "key": "width",
            "label": "Width (pixels)",
            "value": 480,
            "type": "number",
            "min": 16,
            "max": 960,
            "step": 1
          },
          {
            "key": "fps",
            "label": "Frames per second",
            "value": 10,
            "type": "number",
            "min": 1,
            "max": 25,
            "step": 1
          },
          {
            "key": "engine",
            "label": "Processing location",
            "type": "select",
            "value": "browser",
            "values": [
              "browser",
              "server"
            ],
            "labels": {
              "browser": "Browser (files stay here)",
              "server": "Local server (larger files)"
            }
          }
        ],
        "files": true,
        "accept": ".mp4,.mov,.mkv,.webm,.avi",
        "multiple": false,
        "input": false,
        "processing": "Browser or server",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. ",
        "hybrid": true,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/video-to-gif/run",
      "api": {
        "id": "video-to-gif",
        "name": "Video to GIF",
        "category": "image-tools",
        "description": "Turn a short video section into an animated GIF.",
        "notes": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. ",
        "human_path": "/en/image-tools/video-to-gif/",
        "method": "POST",
        "endpoint": "/api/v1/tools/video-to-gif/run",
        "schema_url": "/api/v1/tools/video-to-gif",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "start": {
                  "type": "number",
                  "description": "Start (seconds)",
                  "default": 0.0,
                  "minimum": 0,
                  "maximum": 1800
                },
                "duration": {
                  "type": "number",
                  "description": "Duration (seconds)",
                  "default": 3.0,
                  "minimum": 0.1,
                  "maximum": 15
                },
                "width": {
                  "type": "number",
                  "description": "Width (pixels)",
                  "default": 480.0,
                  "minimum": 16,
                  "maximum": 960,
                  "multipleOf": 1
                },
                "fps": {
                  "type": "number",
                  "description": "Frames per second",
                  "default": 10.0,
                  "minimum": 1,
                  "maximum": 25,
                  "multipleOf": 1
                },
                "engine": {
                  "type": "string",
                  "description": "Processing location",
                  "default": "browser",
                  "enum": [
                    "browser",
                    "server"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/video-to-gif/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/video-to-gif/"
    },
    {
      "id": "watermark-image",
      "category": "image-tools",
      "built": true,
      "requirements": "Text/image watermark, opacity, placement and batch preview; keep original.",
      "implementation": {
        "fields": [
          {
            "key": "caption",
            "label": "Caption / watermark",
            "value": "Happytails.ai",
            "type": "text"
          },
          {
            "key": "fontSize",
            "label": "Font size",
            "value": 36,
            "type": "number"
          },
          {
            "key": "color",
            "label": "Text color",
            "value": "#ffffff",
            "type": "color"
          },
          {
            "key": "opacity",
            "label": "Watermark opacity (0–1)",
            "value": 0.6,
            "type": "number"
          }
        ],
        "files": true,
        "accept": "image/*,.svg,.avif",
        "input": false,
        "note": "Runs in your browser. Animated inputs produce a single still image. Supported decoding depends on your browser.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/watermark-image/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/watermark-image/"
    },
    {
      "id": "webp-to-gif",
      "category": "image-tools",
      "built": true,
      "requirements": "Preserve frames where supported; explain palette/alpha loss.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".webp,.png,.apng",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Processed by the local, self-hosted engine. No third-party conversion service is used. Preserves decoded animation frames and timing. GIF has fewer colours and only binary transparency.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/webp-to-gif/run",
      "api": {
        "id": "webp-to-gif",
        "name": "WEBP to GIF",
        "category": "image-tools",
        "description": "Convert WEBP files to GIF with the available format settings.",
        "notes": "Processed by the local, self-hosted engine. No third-party conversion service is used. Preserves decoded animation frames and timing. GIF has fewer colours and only binary transparency.",
        "human_path": "/en/image-tools/webp-to-gif/",
        "method": "POST",
        "endpoint": "/api/v1/tools/webp-to-gif/run",
        "schema_url": "/api/v1/tools/webp-to-gif",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/webp-to-gif/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/webp-to-gif/"
    },
    {
      "id": "webp-to-jpg",
      "category": "image-tools",
      "built": true,
      "requirements": "Background selection for transparency; JPEG quality preview; handle animation explicitly.",
      "implementation": {
        "fields": [
          {
            "key": "background",
            "label": "JPEG background",
            "value": "#ffffff",
            "type": "color"
          }
        ],
        "files": true,
        "accept": ".webp",
        "input": false,
        "note": "Runs in your browser. Animated inputs produce a single still image. Supported decoding depends on your browser.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/webp-to-jpg/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/webp-to-jpg/"
    },
    {
      "id": "webp-to-png",
      "category": "image-tools",
      "built": true,
      "requirements": "Preserve alpha; identify animated input and define first-frame versus full-animation behavior.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".webp",
        "input": false,
        "note": "Runs in your browser. Animated inputs produce a single still image. Supported decoding depends on your browser.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/image-tools/webp-to-png/",
      "agent_url": "https://happytails.ai/agents/en/image-tools/webp-to-png/"
    },
    {
      "id": "dpi-calculator",
      "category": "maker-tools",
      "built": true,
      "requirements": "Pixel dimensions, physical size and print resolution; distinguish resolution metadata from real detail.",
      "implementation": {
        "fields": [
          {
            "key": "pixels",
            "label": "Pixels",
            "value": 3000,
            "type": "number"
          },
          {
            "key": "inches",
            "label": "Inches",
            "value": 10,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/dpi-calculator/run",
      "api": {
        "id": "dpi-calculator",
        "name": "DPI calculator",
        "category": "maker-tools",
        "description": "Calculate pixel density from pixel count and physical size.",
        "notes": "",
        "human_path": "/en/maker-tools/dpi-calculator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/dpi-calculator/run",
        "schema_url": "/api/v1/tools/dpi-calculator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "pixels": {
                  "type": "number",
                  "description": "Pixels",
                  "default": 3000.0
                },
                "inches": {
                  "type": "number",
                  "description": "Inches",
                  "default": 10.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/maker-tools/dpi-calculator/",
      "agent_url": "https://happytails.ai/agents/en/maker-tools/dpi-calculator/"
    },
    {
      "id": "image-to-stl",
      "category": "maker-tools",
      "built": true,
      "requirements": "Brightness becomes height, with invert option; millimeter dimensions, base thickness and bounded resolution; closed watertight binary STL. Not full 3D object reconstruction.",
      "implementation": {
        "fields": [
          {
            "key": "width",
            "label": "Model width (mm)",
            "value": 100,
            "type": "number",
            "min": 1,
            "max": 500,
            "step": 1
          },
          {
            "key": "height",
            "label": "Relief height (mm)",
            "value": 5,
            "type": "number",
            "min": 1,
            "max": 50,
            "step": 1
          },
          {
            "key": "base",
            "label": "Base thickness (mm)",
            "value": 2,
            "type": "number",
            "min": 1,
            "max": 20,
            "step": 1
          },
          {
            "key": "resolution",
            "label": "Samples on longest side",
            "value": 100,
            "type": "number",
            "min": 8,
            "max": 256,
            "step": 1
          },
          {
            "key": "invert",
            "label": "Darker pixels are higher",
            "value": false,
            "type": "checkbox"
          }
        ],
        "files": true,
        "accept": ".png,.jpg,.jpeg,.webp",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "expansion": true,
        "maxFileBytes": 20971520,
        "note": "Processed on our server with no external conversion service. Creates a solid height-map relief, not a complete 3D object. Transparent pixels use white. Open the STL in a slicer and confirm millimeter units before printing.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/image-to-stl/run",
      "api": {
        "id": "image-to-stl",
        "name": "Image to STL",
        "category": "maker-tools",
        "description": "Turn an image into a solid 3D relief.",
        "notes": "Processed on our server with no external conversion service. Creates a solid height-map relief, not a complete 3D object. Transparent pixels use white. Open the STL in a slicer and confirm millimeter units before printing.",
        "human_path": "/en/maker-tools/image-to-stl/",
        "method": "POST",
        "endpoint": "/api/v1/tools/image-to-stl/run",
        "schema_url": "/api/v1/tools/image-to-stl",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "width": {
                  "type": "number",
                  "description": "Model width (mm)",
                  "default": 100.0,
                  "minimum": 1,
                  "maximum": 500,
                  "multipleOf": 1
                },
                "height": {
                  "type": "number",
                  "description": "Relief height (mm)",
                  "default": 5.0,
                  "minimum": 1,
                  "maximum": 50,
                  "multipleOf": 1
                },
                "base": {
                  "type": "number",
                  "description": "Base thickness (mm)",
                  "default": 2.0,
                  "minimum": 1,
                  "maximum": 20,
                  "multipleOf": 1
                },
                "resolution": {
                  "type": "number",
                  "description": "Samples on longest side",
                  "default": 100.0,
                  "minimum": 8,
                  "maximum": 256,
                  "multipleOf": 1
                },
                "invert": {
                  "type": "boolean",
                  "description": "Darker pixels are higher",
                  "default": false
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/maker-tools/image-to-stl/",
      "agent_url": "https://happytails.ai/agents/en/maker-tools/image-to-stl/"
    },
    {
      "id": "obj-to-stl",
      "category": "maker-tools",
      "built": true,
      "requirements": "Triangulation, units and loss of materials/textures made explicit.",
      "implementation": {
        "fields": [],
        "files": true,
        "input": false,
        "accept": ".obj",
        "note": "Formats do not reliably encode units. Unit selection labels dimensions without rescaling. Mesh conversion does not repair geometry or preserve OBJ materials.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/maker-tools/obj-to-stl/",
      "agent_url": "https://happytails.ai/agents/en/maker-tools/obj-to-stl/"
    },
    {
      "id": "ohms-law",
      "category": "maker-tools",
      "built": true,
      "requirements": "Any two independent electrical quantities; units and invalid-value checks.",
      "implementation": {
        "fields": [
          {
            "key": "volts",
            "label": "Voltage (V)",
            "value": 12,
            "type": "number"
          },
          {
            "key": "ohms",
            "label": "Resistance (Ω)",
            "value": 6,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/ohms-law/run",
      "api": {
        "id": "ohms-law",
        "name": "Ohms law",
        "category": "maker-tools",
        "description": "Calculate current and power from voltage and resistance.",
        "notes": "",
        "human_path": "/en/maker-tools/ohms-law/",
        "method": "POST",
        "endpoint": "/api/v1/tools/ohms-law/run",
        "schema_url": "/api/v1/tools/ohms-law",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "volts": {
                  "type": "number",
                  "description": "Voltage (V)",
                  "default": 12.0
                },
                "ohms": {
                  "type": "number",
                  "description": "Resistance (Ω)",
                  "default": 6.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/maker-tools/ohms-law/",
      "agent_url": "https://happytails.ai/agents/en/maker-tools/ohms-law/"
    },
    {
      "id": "resistor-color-code",
      "category": "maker-tools",
      "built": true,
      "requirements": "4/5/6-band modes and tolerance; color labels accessible without relying on color.",
      "implementation": {
        "fields": [
          {
            "key": "a",
            "label": "First band",
            "value": "brown",
            "type": "select",
            "values": [
              "brown",
              "red",
              "orange",
              "yellow",
              "green",
              "blue",
              "violet",
              "gray",
              "white"
            ]
          },
          {
            "key": "b",
            "label": "Second band",
            "value": "black",
            "type": "select",
            "values": [
              "black",
              "brown",
              "red",
              "orange",
              "yellow",
              "green",
              "blue",
              "violet",
              "gray",
              "white"
            ]
          },
          {
            "key": "multiplier",
            "label": "Multiplier",
            "value": "black",
            "type": "select",
            "values": [
              "black",
              "brown",
              "red",
              "orange",
              "yellow",
              "green",
              "blue"
            ]
          },
          {
            "key": "tolerance",
            "label": "Tolerance",
            "value": "±5% (gold)",
            "type": "select",
            "values": [
              "±5% (gold)",
              "±10% (silver)",
              "±1% (brown)",
              "±2% (red)"
            ]
          }
        ],
        "input": false,
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/resistor-color-code/run",
      "api": {
        "id": "resistor-color-code",
        "name": "Resistor color code",
        "category": "maker-tools",
        "description": "4/5/6-band modes and tolerance.",
        "notes": "",
        "human_path": "/en/maker-tools/resistor-color-code/",
        "method": "POST",
        "endpoint": "/api/v1/tools/resistor-color-code/run",
        "schema_url": "/api/v1/tools/resistor-color-code",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "a": {
                  "type": "string",
                  "description": "First band",
                  "default": "brown",
                  "enum": [
                    "brown",
                    "red",
                    "orange",
                    "yellow",
                    "green",
                    "blue",
                    "violet",
                    "gray",
                    "white"
                  ]
                },
                "b": {
                  "type": "string",
                  "description": "Second band",
                  "default": "black",
                  "enum": [
                    "black",
                    "brown",
                    "red",
                    "orange",
                    "yellow",
                    "green",
                    "blue",
                    "violet",
                    "gray",
                    "white"
                  ]
                },
                "multiplier": {
                  "type": "string",
                  "description": "Multiplier",
                  "default": "black",
                  "enum": [
                    "black",
                    "brown",
                    "red",
                    "orange",
                    "yellow",
                    "green",
                    "blue"
                  ]
                },
                "tolerance": {
                  "type": "string",
                  "description": "Tolerance",
                  "default": "±5% (gold)",
                  "enum": [
                    "±5% (gold)",
                    "±10% (silver)",
                    "±1% (brown)",
                    "±2% (red)"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/maker-tools/resistor-color-code/",
      "agent_url": "https://happytails.ai/agents/en/maker-tools/resistor-color-code/"
    },
    {
      "id": "stl-to-obj",
      "category": "maker-tools",
      "built": true,
      "requirements": "Preserve mesh topology; explain STL lacks reliable material/scale metadata.",
      "implementation": {
        "fields": [],
        "files": true,
        "input": false,
        "accept": ".stl",
        "note": "Formats do not reliably encode units. Unit selection labels dimensions without rescaling. Mesh conversion does not repair geometry or preserve OBJ materials.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/maker-tools/stl-to-obj/",
      "agent_url": "https://happytails.ai/agents/en/maker-tools/stl-to-obj/"
    },
    {
      "id": "stl-viewer",
      "category": "maker-tools",
      "built": true,
      "requirements": "Local mesh rendering, dimensions with chosen units and memory limits.",
      "implementation": {
        "fields": [
          {
            "key": "units",
            "label": "Model units",
            "value": "mm",
            "type": "select",
            "values": [
              "mm",
              "cm",
              "m",
              "in"
            ]
          }
        ],
        "files": true,
        "input": false,
        "accept": ".stl",
        "note": "Formats do not reliably encode units. Unit selection labels dimensions without rescaling. Mesh conversion does not repair geometry or preserve OBJ materials.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/maker-tools/stl-viewer/",
      "agent_url": "https://happytails.ai/agents/en/maker-tools/stl-viewer/"
    },
    {
      "id": "broken-link-checker",
      "category": "marketing-tools",
      "built": true,
      "requirements": "Bounded scan, distinguish transient errors from broken links, protect private networks.",
      "implementation": {
        "fields": [],
        "processing": "Server required",
        "note": "Uses the local diagnostic server to contact the supplied public host or DNS/RDAP provider. Only public internet addresses are permitted; requests time out and redirects are bounded.",
        "experience": {
          "automatic": false,
          "single": true,
          "label": "Website URL",
          "placeholder": "https://happytails.ai",
          "help": "Enter one complete HTTP or HTTPS URL. Only public addresses and ports 80 or 443 are supported.",
          "action": "Check URL"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/broken-link-checker/run",
      "api": {
        "id": "broken-link-checker",
        "name": "Broken link checker",
        "category": "marketing-tools",
        "description": "Bounded scan, distinguish transient errors from broken links, protect private networks.",
        "notes": "Uses the local diagnostic server to contact the supplied public host or DNS/RDAP provider. Only public internet addresses are permitted; requests time out and redirects are bounded.",
        "human_path": "/en/marketing-tools/broken-link-checker/",
        "method": "POST",
        "endpoint": "/api/v1/tools/broken-link-checker/run",
        "schema_url": "/api/v1/tools/broken-link-checker",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; contacts public network services",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": null
        }
      },
      "agent_processing": "Server; contacts public network services",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/marketing-tools/broken-link-checker/",
      "agent_url": "https://happytails.ai/agents/en/marketing-tools/broken-link-checker/"
    },
    {
      "id": "email-qr-code",
      "category": "marketing-tools",
      "built": true,
      "requirements": "mailto payload, subject/body escaping and readable scan test; static output.",
      "implementation": {
        "fields": [
          {
            "key": "correction",
            "label": "Error correction",
            "value": "M",
            "type": "select",
            "values": [
              "M",
              "L",
              "Q",
              "H"
            ]
          },
          {
            "key": "email",
            "label": "Email",
            "value": "",
            "type": "text"
          },
          {
            "key": "message",
            "label": "Message",
            "value": "",
            "type": "text"
          }
        ],
        "input": false,
        "note": "Download an SVG QR code. Anyone who scans it can read its contents; the code does not encrypt your data.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/email-qr-code/run",
      "api": {
        "id": "email-qr-code",
        "name": "Email QR code",
        "category": "marketing-tools",
        "description": "mailto payload, subject/body escaping and readable scan test.",
        "notes": "Download an SVG QR code. Anyone who scans it can read its contents; the code does not encrypt your data.",
        "human_path": "/en/marketing-tools/email-qr-code/",
        "method": "POST",
        "endpoint": "/api/v1/tools/email-qr-code/run",
        "schema_url": "/api/v1/tools/email-qr-code",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "correction": {
                  "type": "string",
                  "description": "Error correction",
                  "default": "M",
                  "enum": [
                    "M",
                    "L",
                    "Q",
                    "H"
                  ]
                },
                "email": {
                  "type": "string",
                  "description": "Email",
                  "default": ""
                },
                "message": {
                  "type": "string",
                  "description": "Message",
                  "default": ""
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/marketing-tools/email-qr-code/",
      "agent_url": "https://happytails.ai/agents/en/marketing-tools/email-qr-code/"
    },
    {
      "id": "event-qr-code",
      "category": "marketing-tools",
      "built": true,
      "requirements": "Validate supported calendar payload and timezone handling; distinguish static event from hosted event page.",
      "implementation": {
        "fields": [
          {
            "key": "correction",
            "label": "Error correction",
            "value": "M",
            "type": "select",
            "values": [
              "M",
              "L",
              "Q",
              "H"
            ]
          },
          {
            "key": "name",
            "label": "Event title",
            "value": "",
            "type": "text"
          },
          {
            "key": "start",
            "label": "Event start UTC (YYYYMMDDTHHMMSSZ)",
            "value": "",
            "type": "text"
          },
          {
            "key": "end",
            "label": "Event end UTC (YYYYMMDDTHHMMSSZ)",
            "value": "",
            "type": "text"
          }
        ],
        "input": false,
        "note": "Download an SVG QR code. Anyone who scans it can read its contents; the code does not encrypt your data.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/event-qr-code/run",
      "api": {
        "id": "event-qr-code",
        "name": "Event QR code",
        "category": "marketing-tools",
        "description": "Validate supported calendar payload and timezone handling.",
        "notes": "Download an SVG QR code. Anyone who scans it can read its contents; the code does not encrypt your data.",
        "human_path": "/en/marketing-tools/event-qr-code/",
        "method": "POST",
        "endpoint": "/api/v1/tools/event-qr-code/run",
        "schema_url": "/api/v1/tools/event-qr-code",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "correction": {
                  "type": "string",
                  "description": "Error correction",
                  "default": "M",
                  "enum": [
                    "M",
                    "L",
                    "Q",
                    "H"
                  ]
                },
                "name": {
                  "type": "string",
                  "description": "Event title",
                  "default": ""
                },
                "start": {
                  "type": "string",
                  "description": "Event start UTC (YYYYMMDDTHHMMSSZ)",
                  "default": ""
                },
                "end": {
                  "type": "string",
                  "description": "Event end UTC (YYYYMMDDTHHMMSSZ)",
                  "default": ""
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/marketing-tools/event-qr-code/",
      "agent_url": "https://happytails.ai/agents/en/marketing-tools/event-qr-code/"
    },
    {
      "id": "open-graph-preview",
      "category": "marketing-tools",
      "built": true,
      "requirements": "Pasted metadata preview first; remote URL fetch requires controlled backend; do not promise exact platform rendering.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/marketing-tools/open-graph-preview/",
      "agent_url": "https://happytails.ai/agents/en/marketing-tools/open-graph-preview/"
    },
    {
      "id": "qr-code-generator",
      "category": "marketing-tools",
      "built": true,
      "requirements": "Static downloadable SVG/PNG with quiet zone and error correction; no expiring redirect dependency.",
      "implementation": {
        "fields": [
          {
            "key": "correction",
            "label": "Error correction",
            "value": "M",
            "type": "select",
            "values": [
              "M",
              "L",
              "Q",
              "H"
            ]
          }
        ],
        "input": true,
        "note": "Download an SVG QR code. Anyone who scans it can read its contents; the code does not encrypt your data.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/qr-code-generator/run",
      "api": {
        "id": "qr-code-generator",
        "name": "QR code generator",
        "category": "marketing-tools",
        "description": "Static downloadable SVG/PNG with quiet zone and error correction.",
        "notes": "Download an SVG QR code. Anyone who scans it can read its contents; the code does not encrypt your data.",
        "human_path": "/en/marketing-tools/qr-code-generator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/qr-code-generator/run",
        "schema_url": "/api/v1/tools/qr-code-generator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "correction": {
                  "type": "string",
                  "description": "Error correction",
                  "default": "M",
                  "enum": [
                    "M",
                    "L",
                    "Q",
                    "H"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/marketing-tools/qr-code-generator/",
      "agent_url": "https://happytails.ai/agents/en/marketing-tools/qr-code-generator/"
    },
    {
      "id": "serp-preview",
      "category": "marketing-tools",
      "built": true,
      "requirements": "Title/description editing with device previews; clearly label simulation and possible search rewrites.",
      "implementation": {
        "fields": [
          {
            "key": "title",
            "label": "Title",
            "value": "",
            "type": "text"
          },
          {
            "key": "description",
            "label": "Description",
            "value": "",
            "type": "text"
          }
        ],
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/serp-preview/run",
      "api": {
        "id": "serp-preview",
        "name": "Serp preview",
        "category": "marketing-tools",
        "description": "Title/description editing with device previews.",
        "notes": "",
        "human_path": "/en/marketing-tools/serp-preview/",
        "method": "POST",
        "endpoint": "/api/v1/tools/serp-preview/run",
        "schema_url": "/api/v1/tools/serp-preview",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "title": {
                  "type": "string",
                  "description": "Title",
                  "default": ""
                },
                "description": {
                  "type": "string",
                  "description": "Description",
                  "default": ""
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/marketing-tools/serp-preview/",
      "agent_url": "https://happytails.ai/agents/en/marketing-tools/serp-preview/"
    },
    {
      "id": "sitemap-generator",
      "category": "marketing-tools",
      "built": true,
      "requirements": "Bounded public-site crawling, canonical filtering and valid XML; cost/rate controls.",
      "implementation": {
        "fields": [],
        "note": "One absolute URL per line. Include only canonical, indexable pages.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/sitemap-generator/run",
      "api": {
        "id": "sitemap-generator",
        "name": "Sitemap generator",
        "category": "marketing-tools",
        "description": "Bounded public-site crawling, canonical filtering and valid XML.",
        "notes": "One absolute URL per line. Include only canonical, indexable pages.",
        "human_path": "/en/marketing-tools/sitemap-generator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/sitemap-generator/run",
        "schema_url": "/api/v1/tools/sitemap-generator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/marketing-tools/sitemap-generator/",
      "agent_url": "https://happytails.ai/agents/en/marketing-tools/sitemap-generator/"
    },
    {
      "id": "sms-qr-code",
      "category": "marketing-tools",
      "built": true,
      "requirements": "Phone/text payload and platform compatibility tests; static output.",
      "implementation": {
        "fields": [
          {
            "key": "correction",
            "label": "Error correction",
            "value": "M",
            "type": "select",
            "values": [
              "M",
              "L",
              "Q",
              "H"
            ]
          },
          {
            "key": "phone",
            "label": "Phone including country code",
            "value": "",
            "type": "text"
          },
          {
            "key": "message",
            "label": "Message",
            "value": "",
            "type": "text"
          }
        ],
        "input": false,
        "note": "Download an SVG QR code. Anyone who scans it can read its contents; the code does not encrypt your data.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/sms-qr-code/run",
      "api": {
        "id": "sms-qr-code",
        "name": "Sms QR code",
        "category": "marketing-tools",
        "description": "Phone/text payload and platform compatibility tests.",
        "notes": "Download an SVG QR code. Anyone who scans it can read its contents; the code does not encrypt your data.",
        "human_path": "/en/marketing-tools/sms-qr-code/",
        "method": "POST",
        "endpoint": "/api/v1/tools/sms-qr-code/run",
        "schema_url": "/api/v1/tools/sms-qr-code",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "correction": {
                  "type": "string",
                  "description": "Error correction",
                  "default": "M",
                  "enum": [
                    "M",
                    "L",
                    "Q",
                    "H"
                  ]
                },
                "phone": {
                  "type": "string",
                  "description": "Phone including country code",
                  "default": ""
                },
                "message": {
                  "type": "string",
                  "description": "Message",
                  "default": ""
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/marketing-tools/sms-qr-code/",
      "agent_url": "https://happytails.ai/agents/en/marketing-tools/sms-qr-code/"
    },
    {
      "id": "utm-builder",
      "category": "marketing-tools",
      "built": true,
      "requirements": "Validate destination, encode parameters and expose duplicates; consistent naming and copy output.",
      "implementation": {
        "fields": [
          {
            "key": "source",
            "label": "UTM source",
            "value": "",
            "type": "text"
          },
          {
            "key": "medium",
            "label": "UTM medium",
            "value": "",
            "type": "text"
          },
          {
            "key": "campaign",
            "label": "UTM campaign",
            "value": "",
            "type": "text"
          },
          {
            "key": "term",
            "label": "UTM term",
            "value": "",
            "type": "text"
          },
          {
            "key": "content",
            "label": "UTM content",
            "value": "",
            "type": "text"
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/utm-builder/run",
      "api": {
        "id": "utm-builder",
        "name": "Utm builder",
        "category": "marketing-tools",
        "description": "Validate destination, encode parameters and expose duplicates.",
        "notes": "",
        "human_path": "/en/marketing-tools/utm-builder/",
        "method": "POST",
        "endpoint": "/api/v1/tools/utm-builder/run",
        "schema_url": "/api/v1/tools/utm-builder",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "source": {
                  "type": "string",
                  "description": "UTM source",
                  "default": ""
                },
                "medium": {
                  "type": "string",
                  "description": "UTM medium",
                  "default": ""
                },
                "campaign": {
                  "type": "string",
                  "description": "UTM campaign",
                  "default": ""
                },
                "term": {
                  "type": "string",
                  "description": "UTM term",
                  "default": ""
                },
                "content": {
                  "type": "string",
                  "description": "UTM content",
                  "default": ""
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/marketing-tools/utm-builder/",
      "agent_url": "https://happytails.ai/agents/en/marketing-tools/utm-builder/"
    },
    {
      "id": "vcard-qr-code",
      "category": "marketing-tools",
      "built": true,
      "requirements": "Versioned vCard fields, escaped newlines and realistic payload density; test imports.",
      "implementation": {
        "fields": [
          {
            "key": "correction",
            "label": "Error correction",
            "value": "M",
            "type": "select",
            "values": [
              "M",
              "L",
              "Q",
              "H"
            ]
          },
          {
            "key": "name",
            "label": "Full name",
            "value": "",
            "type": "text"
          },
          {
            "key": "phone",
            "label": "Phone including country code",
            "value": "",
            "type": "text"
          },
          {
            "key": "email",
            "label": "Email",
            "value": "",
            "type": "text"
          }
        ],
        "input": false,
        "note": "Download an SVG QR code. Anyone who scans it can read its contents; the code does not encrypt your data.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/vcard-qr-code/run",
      "api": {
        "id": "vcard-qr-code",
        "name": "Vcard QR code",
        "category": "marketing-tools",
        "description": "Versioned vCard fields, escaped newlines and realistic payload density.",
        "notes": "Download an SVG QR code. Anyone who scans it can read its contents; the code does not encrypt your data.",
        "human_path": "/en/marketing-tools/vcard-qr-code/",
        "method": "POST",
        "endpoint": "/api/v1/tools/vcard-qr-code/run",
        "schema_url": "/api/v1/tools/vcard-qr-code",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "correction": {
                  "type": "string",
                  "description": "Error correction",
                  "default": "M",
                  "enum": [
                    "M",
                    "L",
                    "Q",
                    "H"
                  ]
                },
                "name": {
                  "type": "string",
                  "description": "Full name",
                  "default": ""
                },
                "phone": {
                  "type": "string",
                  "description": "Phone including country code",
                  "default": ""
                },
                "email": {
                  "type": "string",
                  "description": "Email",
                  "default": ""
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/marketing-tools/vcard-qr-code/",
      "agent_url": "https://happytails.ai/agents/en/marketing-tools/vcard-qr-code/"
    },
    {
      "id": "whatsapp-link",
      "category": "marketing-tools",
      "built": true,
      "requirements": "International number and percent-encoded message; no messaging or contact lookup.",
      "implementation": {
        "fields": [
          {
            "key": "message",
            "label": "Message",
            "value": "",
            "type": "text"
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/whatsapp-link/run",
      "api": {
        "id": "whatsapp-link",
        "name": "Whatsapp link",
        "category": "marketing-tools",
        "description": "International number and percent-encoded message.",
        "notes": "",
        "human_path": "/en/marketing-tools/whatsapp-link/",
        "method": "POST",
        "endpoint": "/api/v1/tools/whatsapp-link/run",
        "schema_url": "/api/v1/tools/whatsapp-link",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "message": {
                  "type": "string",
                  "description": "Message",
                  "default": ""
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/marketing-tools/whatsapp-link/",
      "agent_url": "https://happytails.ai/agents/en/marketing-tools/whatsapp-link/"
    },
    {
      "id": "wifi-qr-code",
      "category": "marketing-tools",
      "built": true,
      "requirements": "SSID/password/auth fields and proper escaping; explain scan compatibility and local processing.",
      "implementation": {
        "fields": [
          {
            "key": "correction",
            "label": "Error correction",
            "value": "M",
            "type": "select",
            "values": [
              "M",
              "L",
              "Q",
              "H"
            ]
          },
          {
            "key": "name",
            "label": "Network name (SSID)",
            "value": "",
            "type": "text"
          },
          {
            "key": "password",
            "label": "Wi-Fi password",
            "value": "",
            "type": "password"
          },
          {
            "key": "security",
            "label": "Wi-Fi security",
            "value": "WPA",
            "type": "select",
            "values": [
              "WPA",
              "WEP",
              "nopass"
            ]
          }
        ],
        "input": false,
        "note": "Download an SVG QR code. Anyone who scans it can read its contents; the code does not encrypt your data.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/wifi-qr-code/run",
      "api": {
        "id": "wifi-qr-code",
        "name": "Wifi QR code",
        "category": "marketing-tools",
        "description": "SSID/password/auth fields and proper escaping.",
        "notes": "Download an SVG QR code. Anyone who scans it can read its contents; the code does not encrypt your data.",
        "human_path": "/en/marketing-tools/wifi-qr-code/",
        "method": "POST",
        "endpoint": "/api/v1/tools/wifi-qr-code/run",
        "schema_url": "/api/v1/tools/wifi-qr-code",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "correction": {
                  "type": "string",
                  "description": "Error correction",
                  "default": "M",
                  "enum": [
                    "M",
                    "L",
                    "Q",
                    "H"
                  ]
                },
                "name": {
                  "type": "string",
                  "description": "Network name (SSID)",
                  "default": ""
                },
                "password": {
                  "type": "string",
                  "description": "Wi-Fi password",
                  "default": ""
                },
                "security": {
                  "type": "string",
                  "description": "Wi-Fi security",
                  "default": "WPA",
                  "enum": [
                    "WPA",
                    "WEP",
                    "nopass"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/marketing-tools/wifi-qr-code/",
      "agent_url": "https://happytails.ai/agents/en/marketing-tools/wifi-qr-code/"
    },
    {
      "id": "add-subtitles-to-video",
      "category": "media-tools",
      "built": true,
      "requirements": "Separate soft-track muxing from hardcoded captions; font and layout tests.",
      "implementation": {
        "fields": [
          {
            "key": "engine",
            "label": "Processing location",
            "type": "select",
            "value": "browser",
            "values": [
              "browser",
              "server"
            ],
            "labels": {
              "browser": "Browser (files stay here)",
              "server": "Local server (larger files)"
            }
          }
        ],
        "files": true,
        "accept": ".mp4,.mov,.mkv,.webm,.avi,.srt",
        "multiple": true,
        "input": false,
        "processing": "Browser or server",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Choose one video and one SRT file. Adds a selectable subtitle track to MP4; subtitles are not burned into the picture.",
        "hybrid": true,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/add-subtitles-to-video/run",
      "api": {
        "id": "add-subtitles-to-video",
        "name": "Add subtitles to video",
        "category": "media-tools",
        "description": "Add an SRT subtitle track to a video.",
        "notes": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Choose one video and one SRT file. Adds a selectable subtitle track to MP4; subtitles are not burned into the picture.",
        "human_path": "/en/media-tools/add-subtitles-to-video/",
        "method": "POST",
        "endpoint": "/api/v1/tools/add-subtitles-to-video/run",
        "schema_url": "/api/v1/tools/add-subtitles-to-video",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "engine": {
                  "type": "string",
                  "description": "Processing location",
                  "default": "browser",
                  "enum": [
                    "browser",
                    "server"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 20,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 20,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/media-tools/add-subtitles-to-video/",
      "agent_url": "https://happytails.ai/agents/en/media-tools/add-subtitles-to-video/"
    },
    {
      "id": "change-audio-speed",
      "category": "media-tools",
      "built": true,
      "requirements": "Playback speed with optional pitch preservation and output preview.",
      "implementation": {
        "fields": [
          {
            "key": "speed",
            "label": "Speed multiplier",
            "value": 1.25,
            "type": "number",
            "min": 0.5,
            "max": 2,
            "step": "any"
          },
          {
            "key": "engine",
            "label": "Processing location",
            "type": "select",
            "value": "browser",
            "values": [
              "browser",
              "server"
            ],
            "labels": {
              "browser": "Browser (files stay here)",
              "server": "Local server (larger files)"
            }
          }
        ],
        "files": true,
        "accept": ".mp3,.wav,.m4a,.aac,.flac,.ogg,.opus",
        "multiple": false,
        "input": false,
        "processing": "Browser or server",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Preserves pitch and exports WAV.",
        "hybrid": true,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/change-audio-speed/run",
      "api": {
        "id": "change-audio-speed",
        "name": "Change audio speed",
        "category": "media-tools",
        "description": "Change audio playback speed while preserving pitch.",
        "notes": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Preserves pitch and exports WAV.",
        "human_path": "/en/media-tools/change-audio-speed/",
        "method": "POST",
        "endpoint": "/api/v1/tools/change-audio-speed/run",
        "schema_url": "/api/v1/tools/change-audio-speed",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "speed": {
                  "type": "number",
                  "description": "Speed multiplier",
                  "default": 1.25,
                  "minimum": 0.5,
                  "maximum": 2
                },
                "engine": {
                  "type": "string",
                  "description": "Processing location",
                  "default": "browser",
                  "enum": [
                    "browser",
                    "server"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/media-tools/change-audio-speed/",
      "agent_url": "https://happytails.ai/agents/en/media-tools/change-audio-speed/"
    },
    {
      "id": "change-video-speed",
      "category": "media-tools",
      "built": true,
      "requirements": "Video/audio timebase alignment and pitch behavior; preview duration.",
      "implementation": {
        "fields": [
          {
            "key": "speed",
            "label": "Speed multiplier",
            "value": 1.25,
            "type": "number",
            "min": 0.5,
            "max": 2,
            "step": "any"
          },
          {
            "key": "engine",
            "label": "Processing location",
            "type": "select",
            "value": "browser",
            "values": [
              "browser",
              "server"
            ],
            "labels": {
              "browser": "Browser (files stay here)",
              "server": "Local server (larger files)"
            }
          }
        ],
        "files": true,
        "accept": ".mp4,.mov,.mkv,.webm,.avi",
        "multiple": false,
        "input": false,
        "processing": "Browser or server",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Adjusts video timing and audio speed together, preserving audio pitch.",
        "hybrid": true,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/change-video-speed/run",
      "api": {
        "id": "change-video-speed",
        "name": "Change video speed",
        "category": "media-tools",
        "description": "Speed up or slow down a video and its audio.",
        "notes": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Adjusts video timing and audio speed together, preserving audio pitch.",
        "human_path": "/en/media-tools/change-video-speed/",
        "method": "POST",
        "endpoint": "/api/v1/tools/change-video-speed/run",
        "schema_url": "/api/v1/tools/change-video-speed",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "speed": {
                  "type": "number",
                  "description": "Speed multiplier",
                  "default": 1.25,
                  "minimum": 0.5,
                  "maximum": 2
                },
                "engine": {
                  "type": "string",
                  "description": "Processing location",
                  "default": "browser",
                  "enum": [
                    "browser",
                    "server"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/media-tools/change-video-speed/",
      "agent_url": "https://happytails.ai/agents/en/media-tools/change-video-speed/"
    },
    {
      "id": "compress-audio",
      "category": "media-tools",
      "built": true,
      "requirements": "Clarify file-size compression versus dynamic-range compression; preview bytes/quality.",
      "implementation": {
        "fields": [
          {
            "key": "bitrate",
            "label": "MP3 bitrate (kbps)",
            "value": "128",
            "type": "select",
            "values": [
              "64",
              "96",
              "128",
              "192",
              "256",
              "320"
            ]
          },
          {
            "key": "engine",
            "label": "Processing location",
            "type": "select",
            "value": "browser",
            "values": [
              "browser",
              "server"
            ],
            "labels": {
              "browser": "Browser (files stay here)",
              "server": "Local server (larger files)"
            }
          }
        ],
        "files": true,
        "accept": ".mp3,.wav,.m4a,.aac,.flac,.ogg,.opus",
        "multiple": false,
        "input": false,
        "processing": "Browser or server",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Audio is processed locally with FFmpeg. Lossy conversion does not recover lost detail.",
        "hybrid": true,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/compress-audio/run",
      "api": {
        "id": "compress-audio",
        "name": "Compress audio",
        "category": "media-tools",
        "description": "Export audio as an MP3 at your chosen bitrate.",
        "notes": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Audio is processed locally with FFmpeg. Lossy conversion does not recover lost detail.",
        "human_path": "/en/media-tools/compress-audio/",
        "method": "POST",
        "endpoint": "/api/v1/tools/compress-audio/run",
        "schema_url": "/api/v1/tools/compress-audio",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "bitrate": {
                  "type": "string",
                  "description": "MP3 bitrate (kbps)",
                  "default": "128",
                  "enum": [
                    "64",
                    "96",
                    "128",
                    "192",
                    "256",
                    "320"
                  ]
                },
                "engine": {
                  "type": "string",
                  "description": "Processing location",
                  "default": "browser",
                  "enum": [
                    "browser",
                    "server"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/media-tools/compress-audio/",
      "agent_url": "https://happytails.ai/agents/en/media-tools/compress-audio/"
    },
    {
      "id": "compress-video",
      "category": "media-tools",
      "built": true,
      "requirements": "Resolution, bitrate and codec controls; explain time/quality tradeoff and device limits.",
      "implementation": {
        "fields": [
          {
            "key": "quality",
            "label": "Quality setting (CRF, lower is sharper)",
            "value": 28,
            "type": "number",
            "min": 18,
            "max": 40,
            "step": 1
          },
          {
            "key": "engine",
            "label": "Processing location",
            "type": "select",
            "value": "browser",
            "values": [
              "browser",
              "server"
            ],
            "labels": {
              "browser": "Browser (files stay here)",
              "server": "Local server (larger files)"
            }
          }
        ],
        "files": true,
        "accept": ".mp4,.mov,.mkv,.webm,.avi",
        "multiple": false,
        "input": false,
        "processing": "Browser or server",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Exports H.264 video and AAC audio in MP4. The first video/audio tracks are used; subtitle and extra tracks are omitted.",
        "hybrid": true,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/compress-video/run",
      "api": {
        "id": "compress-video",
        "name": "Compress video",
        "category": "media-tools",
        "description": "Re-encode a video with an adjustable quality setting.",
        "notes": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Exports H.264 video and AAC audio in MP4. The first video/audio tracks are used; subtitle and extra tracks are omitted.",
        "human_path": "/en/media-tools/compress-video/",
        "method": "POST",
        "endpoint": "/api/v1/tools/compress-video/run",
        "schema_url": "/api/v1/tools/compress-video",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "quality": {
                  "type": "number",
                  "description": "Quality setting (CRF, lower is sharper)",
                  "default": 28.0,
                  "minimum": 18,
                  "maximum": 40,
                  "multipleOf": 1
                },
                "engine": {
                  "type": "string",
                  "description": "Processing location",
                  "default": "browser",
                  "enum": [
                    "browser",
                    "server"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/media-tools/compress-video/",
      "agent_url": "https://happytails.ai/agents/en/media-tools/compress-video/"
    },
    {
      "id": "crop-video",
      "category": "media-tools",
      "built": true,
      "requirements": "Visual crop boundaries and aspect presets; preserve sync.",
      "implementation": {
        "fields": [
          {
            "key": "x",
            "label": "Left (pixels)",
            "value": 0,
            "type": "number",
            "min": 0,
            "max": 4096,
            "step": 1
          },
          {
            "key": "y",
            "label": "Top (pixels)",
            "value": 0,
            "type": "number",
            "min": 0,
            "max": 4096,
            "step": 1
          },
          {
            "key": "width",
            "label": "Width (pixels, even number)",
            "value": 320,
            "type": "number",
            "min": 16,
            "max": 1920,
            "step": 2
          },
          {
            "key": "height",
            "label": "Height (pixels, even number)",
            "value": 240,
            "type": "number",
            "min": 16,
            "max": 1080,
            "step": 2
          },
          {
            "key": "engine",
            "label": "Processing location",
            "type": "select",
            "value": "browser",
            "values": [
              "browser",
              "server"
            ],
            "labels": {
              "browser": "Browser (files stay here)",
              "server": "Local server (larger files)"
            }
          }
        ],
        "files": true,
        "accept": ".mp4,.mov,.mkv,.webm,.avi",
        "multiple": false,
        "input": false,
        "processing": "Browser or server",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. ",
        "hybrid": true,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/crop-video/run",
      "api": {
        "id": "crop-video",
        "name": "Crop video",
        "category": "media-tools",
        "description": "Keep a rectangular region of a video.",
        "notes": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. ",
        "human_path": "/en/media-tools/crop-video/",
        "method": "POST",
        "endpoint": "/api/v1/tools/crop-video/run",
        "schema_url": "/api/v1/tools/crop-video",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "x": {
                  "type": "number",
                  "description": "Left (pixels)",
                  "default": 0.0,
                  "minimum": 0,
                  "maximum": 4096,
                  "multipleOf": 1
                },
                "y": {
                  "type": "number",
                  "description": "Top (pixels)",
                  "default": 0.0,
                  "minimum": 0,
                  "maximum": 4096,
                  "multipleOf": 1
                },
                "width": {
                  "type": "number",
                  "description": "Width (pixels, even number)",
                  "default": 320.0,
                  "minimum": 16,
                  "maximum": 1920
                },
                "height": {
                  "type": "number",
                  "description": "Height (pixels, even number)",
                  "default": 240.0,
                  "minimum": 16,
                  "maximum": 1080
                },
                "engine": {
                  "type": "string",
                  "description": "Processing location",
                  "default": "browser",
                  "enum": [
                    "browser",
                    "server"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/media-tools/crop-video/",
      "agent_url": "https://happytails.ai/agents/en/media-tools/crop-video/"
    },
    {
      "id": "flac-to-mp3",
      "category": "media-tools",
      "built": true,
      "requirements": "Lossless input to lossy output; bitrate and metadata handling.",
      "implementation": {
        "fields": [
          {
            "key": "bitrate",
            "label": "MP3 bitrate (kbps)",
            "value": "128",
            "type": "select",
            "values": [
              "64",
              "96",
              "128",
              "192",
              "256",
              "320"
            ]
          },
          {
            "key": "engine",
            "label": "Processing location",
            "type": "select",
            "value": "browser",
            "values": [
              "browser",
              "server"
            ],
            "labels": {
              "browser": "Browser (files stay here)",
              "server": "Local server (larger files)"
            }
          }
        ],
        "files": true,
        "accept": ".mp3,.wav,.m4a,.aac,.flac,.ogg,.opus",
        "multiple": false,
        "input": false,
        "processing": "Browser or server",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Audio is processed locally with FFmpeg. Lossy conversion does not recover lost detail.",
        "hybrid": true,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/flac-to-mp3/run",
      "api": {
        "id": "flac-to-mp3",
        "name": "Flac to MP3",
        "category": "media-tools",
        "description": "Convert FLAC files to MP3 with the available format settings.",
        "notes": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Audio is processed locally with FFmpeg. Lossy conversion does not recover lost detail.",
        "human_path": "/en/media-tools/flac-to-mp3/",
        "method": "POST",
        "endpoint": "/api/v1/tools/flac-to-mp3/run",
        "schema_url": "/api/v1/tools/flac-to-mp3",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "bitrate": {
                  "type": "string",
                  "description": "MP3 bitrate (kbps)",
                  "default": "128",
                  "enum": [
                    "64",
                    "96",
                    "128",
                    "192",
                    "256",
                    "320"
                  ]
                },
                "engine": {
                  "type": "string",
                  "description": "Processing location",
                  "default": "browser",
                  "enum": [
                    "browser",
                    "server"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/media-tools/flac-to-mp3/",
      "agent_url": "https://happytails.ai/agents/en/media-tools/flac-to-mp3/"
    },
    {
      "id": "increase-audio-volume",
      "category": "media-tools",
      "built": true,
      "requirements": "Gain control, clipping warnings and normalization option.",
      "implementation": {
        "fields": [
          {
            "key": "gain",
            "label": "Gain (decibels)",
            "value": 3,
            "type": "number",
            "min": -30,
            "max": 20,
            "step": "any"
          },
          {
            "key": "engine",
            "label": "Processing location",
            "type": "select",
            "value": "browser",
            "values": [
              "browser",
              "server"
            ],
            "labels": {
              "browser": "Browser (files stay here)",
              "server": "Local server (larger files)"
            }
          }
        ],
        "files": true,
        "accept": ".mp3,.wav,.m4a,.aac,.flac,.ogg,.opus",
        "multiple": false,
        "input": false,
        "processing": "Browser or server",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Uses a limiter to reduce clipping and exports WAV.",
        "hybrid": true,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/increase-audio-volume/run",
      "api": {
        "id": "increase-audio-volume",
        "name": "Increase audio volume",
        "category": "media-tools",
        "description": "Adjust audio gain with a limiter to control peaks.",
        "notes": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Uses a limiter to reduce clipping and exports WAV.",
        "human_path": "/en/media-tools/increase-audio-volume/",
        "method": "POST",
        "endpoint": "/api/v1/tools/increase-audio-volume/run",
        "schema_url": "/api/v1/tools/increase-audio-volume",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "gain": {
                  "type": "number",
                  "description": "Gain (decibels)",
                  "default": 3.0,
                  "minimum": -30,
                  "maximum": 20
                },
                "engine": {
                  "type": "string",
                  "description": "Processing location",
                  "default": "browser",
                  "enum": [
                    "browser",
                    "server"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/media-tools/increase-audio-volume/",
      "agent_url": "https://happytails.ai/agents/en/media-tools/increase-audio-volume/"
    },
    {
      "id": "m4a-to-mp3",
      "category": "media-tools",
      "built": true,
      "requirements": "Distinguish AAC/ALAC inputs and supported decoding; avoid claiming lossless MP3.",
      "implementation": {
        "fields": [
          {
            "key": "bitrate",
            "label": "MP3 bitrate (kbps)",
            "value": "128",
            "type": "select",
            "values": [
              "64",
              "96",
              "128",
              "192",
              "256",
              "320"
            ]
          },
          {
            "key": "engine",
            "label": "Processing location",
            "type": "select",
            "value": "browser",
            "values": [
              "browser",
              "server"
            ],
            "labels": {
              "browser": "Browser (files stay here)",
              "server": "Local server (larger files)"
            }
          }
        ],
        "files": true,
        "accept": ".mp3,.wav,.m4a,.aac,.flac,.ogg,.opus",
        "multiple": false,
        "input": false,
        "processing": "Browser or server",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Audio is processed locally with FFmpeg. Lossy conversion does not recover lost detail.",
        "hybrid": true,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/m4a-to-mp3/run",
      "api": {
        "id": "m4a-to-mp3",
        "name": "M4a to MP3",
        "category": "media-tools",
        "description": "Convert M4A files to MP3 with the available format settings.",
        "notes": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Audio is processed locally with FFmpeg. Lossy conversion does not recover lost detail.",
        "human_path": "/en/media-tools/m4a-to-mp3/",
        "method": "POST",
        "endpoint": "/api/v1/tools/m4a-to-mp3/run",
        "schema_url": "/api/v1/tools/m4a-to-mp3",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "bitrate": {
                  "type": "string",
                  "description": "MP3 bitrate (kbps)",
                  "default": "128",
                  "enum": [
                    "64",
                    "96",
                    "128",
                    "192",
                    "256",
                    "320"
                  ]
                },
                "engine": {
                  "type": "string",
                  "description": "Processing location",
                  "default": "browser",
                  "enum": [
                    "browser",
                    "server"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/media-tools/m4a-to-mp3/",
      "agent_url": "https://happytails.ai/agents/en/media-tools/m4a-to-mp3/"
    },
    {
      "id": "merge-audio",
      "category": "media-tools",
      "built": true,
      "requirements": "Order clips and normalize format; optional gaps/crossfades tested.",
      "implementation": {
        "fields": [
          {
            "key": "engine",
            "label": "Processing location",
            "type": "select",
            "value": "browser",
            "values": [
              "browser",
              "server"
            ],
            "labels": {
              "browser": "Browser (files stay here)",
              "server": "Local server (larger files)"
            }
          }
        ],
        "files": true,
        "accept": ".mp3,.wav,.m4a,.aac,.flac,.ogg,.opus",
        "multiple": true,
        "input": false,
        "processing": "Browser or server",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Joins files in the selected order, resampling to stereo 44.1 kHz WAV.",
        "hybrid": true,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/merge-audio/run",
      "api": {
        "id": "merge-audio",
        "name": "Merge audio",
        "category": "media-tools",
        "description": "Join audio clips in the order you choose.",
        "notes": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Joins files in the selected order, resampling to stereo 44.1 kHz WAV.",
        "human_path": "/en/media-tools/merge-audio/",
        "method": "POST",
        "endpoint": "/api/v1/tools/merge-audio/run",
        "schema_url": "/api/v1/tools/merge-audio",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "engine": {
                  "type": "string",
                  "description": "Processing location",
                  "default": "browser",
                  "enum": [
                    "browser",
                    "server"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 20,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 20,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/media-tools/merge-audio/",
      "agent_url": "https://happytails.ai/agents/en/media-tools/merge-audio/"
    },
    {
      "id": "merge-video",
      "category": "media-tools",
      "built": true,
      "requirements": "Clip ordering, aspect ratio and audio tracks; test output sync.",
      "implementation": {
        "fields": [
          {
            "key": "engine",
            "label": "Processing location",
            "type": "select",
            "value": "browser",
            "values": [
              "browser",
              "server"
            ],
            "labels": {
              "browser": "Browser (files stay here)",
              "server": "Local server (larger files)"
            }
          }
        ],
        "files": true,
        "accept": ".mp4,.mov,.mkv,.webm,.avi",
        "multiple": true,
        "input": false,
        "processing": "Browser or server",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Joins clips in order at 640 × 360. All clips must either have audio or have no audio.",
        "hybrid": true,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/merge-video/run",
      "api": {
        "id": "merge-video",
        "name": "Merge video",
        "category": "media-tools",
        "description": "Join clips into one video with a consistent frame size.",
        "notes": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Joins clips in order at 640 × 360. All clips must either have audio or have no audio.",
        "human_path": "/en/media-tools/merge-video/",
        "method": "POST",
        "endpoint": "/api/v1/tools/merge-video/run",
        "schema_url": "/api/v1/tools/merge-video",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "engine": {
                  "type": "string",
                  "description": "Processing location",
                  "default": "browser",
                  "enum": [
                    "browser",
                    "server"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 20,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 20,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/media-tools/merge-video/",
      "agent_url": "https://happytails.ai/agents/en/media-tools/merge-video/"
    },
    {
      "id": "mkv-to-mp4",
      "category": "media-tools",
      "built": true,
      "requirements": "Select tracks/subtitles; report what survives container change.",
      "implementation": {
        "fields": [
          {
            "key": "quality",
            "label": "Quality setting (CRF, lower is sharper)",
            "value": 28,
            "type": "number",
            "min": 18,
            "max": 40,
            "step": 1
          },
          {
            "key": "engine",
            "label": "Processing location",
            "type": "select",
            "value": "browser",
            "values": [
              "browser",
              "server"
            ],
            "labels": {
              "browser": "Browser (files stay here)",
              "server": "Local server (larger files)"
            }
          }
        ],
        "files": true,
        "accept": ".mp4,.mov,.mkv,.webm,.avi",
        "multiple": false,
        "input": false,
        "processing": "Browser or server",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Exports H.264 video and AAC audio in MP4. The first video/audio tracks are used; subtitle and extra tracks are omitted.",
        "hybrid": true,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/mkv-to-mp4/run",
      "api": {
        "id": "mkv-to-mp4",
        "name": "Mkv to MP4",
        "category": "media-tools",
        "description": "Convert MKV files to MP4 with the available format settings.",
        "notes": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Exports H.264 video and AAC audio in MP4. The first video/audio tracks are used; subtitle and extra tracks are omitted.",
        "human_path": "/en/media-tools/mkv-to-mp4/",
        "method": "POST",
        "endpoint": "/api/v1/tools/mkv-to-mp4/run",
        "schema_url": "/api/v1/tools/mkv-to-mp4",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "quality": {
                  "type": "number",
                  "description": "Quality setting (CRF, lower is sharper)",
                  "default": 28.0,
                  "minimum": 18,
                  "maximum": 40,
                  "multipleOf": 1
                },
                "engine": {
                  "type": "string",
                  "description": "Processing location",
                  "default": "browser",
                  "enum": [
                    "browser",
                    "server"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/media-tools/mkv-to-mp4/",
      "agent_url": "https://happytails.ai/agents/en/media-tools/mkv-to-mp4/"
    },
    {
      "id": "mov-to-mp4",
      "category": "media-tools",
      "built": true,
      "requirements": "Distinguish remuxing from transcoding; choose compatible video/audio codecs.",
      "implementation": {
        "fields": [
          {
            "key": "quality",
            "label": "Quality setting (CRF, lower is sharper)",
            "value": 28,
            "type": "number",
            "min": 18,
            "max": 40,
            "step": 1
          },
          {
            "key": "engine",
            "label": "Processing location",
            "type": "select",
            "value": "browser",
            "values": [
              "browser",
              "server"
            ],
            "labels": {
              "browser": "Browser (files stay here)",
              "server": "Local server (larger files)"
            }
          }
        ],
        "files": true,
        "accept": ".mp4,.mov,.mkv,.webm,.avi",
        "multiple": false,
        "input": false,
        "processing": "Browser or server",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Exports H.264 video and AAC audio in MP4. The first video/audio tracks are used; subtitle and extra tracks are omitted.",
        "hybrid": true,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/mov-to-mp4/run",
      "api": {
        "id": "mov-to-mp4",
        "name": "Mov to MP4",
        "category": "media-tools",
        "description": "Convert MOV files to MP4 with the available format settings.",
        "notes": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Exports H.264 video and AAC audio in MP4. The first video/audio tracks are used; subtitle and extra tracks are omitted.",
        "human_path": "/en/media-tools/mov-to-mp4/",
        "method": "POST",
        "endpoint": "/api/v1/tools/mov-to-mp4/run",
        "schema_url": "/api/v1/tools/mov-to-mp4",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "quality": {
                  "type": "number",
                  "description": "Quality setting (CRF, lower is sharper)",
                  "default": 28.0,
                  "minimum": 18,
                  "maximum": 40,
                  "multipleOf": 1
                },
                "engine": {
                  "type": "string",
                  "description": "Processing location",
                  "default": "browser",
                  "enum": [
                    "browser",
                    "server"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/media-tools/mov-to-mp4/",
      "agent_url": "https://happytails.ai/agents/en/media-tools/mov-to-mp4/"
    },
    {
      "id": "mp3-to-wav",
      "category": "media-tools",
      "built": true,
      "requirements": "Explain no recovery of lost detail; sample-rate/channel selection.",
      "implementation": {
        "fields": [
          {
            "key": "engine",
            "label": "Processing location",
            "type": "select",
            "value": "browser",
            "values": [
              "browser",
              "server"
            ],
            "labels": {
              "browser": "Browser (files stay here)",
              "server": "Local server (larger files)"
            }
          }
        ],
        "files": true,
        "accept": ".mp3,.wav,.m4a,.aac,.flac,.ogg,.opus",
        "multiple": false,
        "input": false,
        "processing": "Browser or server",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Audio is processed locally with FFmpeg. Lossy conversion does not recover lost detail.",
        "hybrid": true,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/mp3-to-wav/run",
      "api": {
        "id": "mp3-to-wav",
        "name": "MP3 to WAV",
        "category": "media-tools",
        "description": "Convert MP3 files to WAV with the available format settings.",
        "notes": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Audio is processed locally with FFmpeg. Lossy conversion does not recover lost detail.",
        "human_path": "/en/media-tools/mp3-to-wav/",
        "method": "POST",
        "endpoint": "/api/v1/tools/mp3-to-wav/run",
        "schema_url": "/api/v1/tools/mp3-to-wav",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "engine": {
                  "type": "string",
                  "description": "Processing location",
                  "default": "browser",
                  "enum": [
                    "browser",
                    "server"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/media-tools/mp3-to-wav/",
      "agent_url": "https://happytails.ai/agents/en/media-tools/mp3-to-wav/"
    },
    {
      "id": "mp4-to-mp3",
      "category": "media-tools",
      "built": true,
      "requirements": "Choose audio track and bitrate; handle videos without audio; disclose transcoding loss.",
      "implementation": {
        "fields": [
          {
            "key": "bitrate",
            "label": "MP3 bitrate (kbps)",
            "value": "128",
            "type": "select",
            "values": [
              "64",
              "96",
              "128",
              "192",
              "256",
              "320"
            ]
          },
          {
            "key": "engine",
            "label": "Processing location",
            "type": "select",
            "value": "browser",
            "values": [
              "browser",
              "server"
            ],
            "labels": {
              "browser": "Browser (files stay here)",
              "server": "Local server (larger files)"
            }
          }
        ],
        "files": true,
        "accept": ".mp4,.mov,.mkv,.webm,.avi",
        "multiple": false,
        "input": false,
        "processing": "Browser or server",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Audio is processed locally with FFmpeg. Lossy conversion does not recover lost detail.",
        "hybrid": true,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/mp4-to-mp3/run",
      "api": {
        "id": "mp4-to-mp3",
        "name": "MP4 to MP3",
        "category": "media-tools",
        "description": "Convert MP4 files to MP3 with the available format settings.",
        "notes": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Audio is processed locally with FFmpeg. Lossy conversion does not recover lost detail.",
        "human_path": "/en/media-tools/mp4-to-mp3/",
        "method": "POST",
        "endpoint": "/api/v1/tools/mp4-to-mp3/run",
        "schema_url": "/api/v1/tools/mp4-to-mp3",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "bitrate": {
                  "type": "string",
                  "description": "MP3 bitrate (kbps)",
                  "default": "128",
                  "enum": [
                    "64",
                    "96",
                    "128",
                    "192",
                    "256",
                    "320"
                  ]
                },
                "engine": {
                  "type": "string",
                  "description": "Processing location",
                  "default": "browser",
                  "enum": [
                    "browser",
                    "server"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/media-tools/mp4-to-mp3/",
      "agent_url": "https://happytails.ai/agents/en/media-tools/mp4-to-mp3/"
    },
    {
      "id": "mute-video",
      "category": "media-tools",
      "built": true,
      "requirements": "Remove audio tracks and verify saved output is silent.",
      "implementation": {
        "fields": [
          {
            "key": "engine",
            "label": "Processing location",
            "type": "select",
            "value": "browser",
            "values": [
              "browser",
              "server"
            ],
            "labels": {
              "browser": "Browser (files stay here)",
              "server": "Local server (larger files)"
            }
          }
        ],
        "files": true,
        "accept": ".mp4,.mov,.mkv,.webm,.avi",
        "multiple": false,
        "input": false,
        "processing": "Browser or server",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Removes audio tracks from the exported MP4.",
        "hybrid": true,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/mute-video/run",
      "api": {
        "id": "mute-video",
        "name": "Mute video",
        "category": "media-tools",
        "description": "Remove a video’s audio track.",
        "notes": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Removes audio tracks from the exported MP4.",
        "human_path": "/en/media-tools/mute-video/",
        "method": "POST",
        "endpoint": "/api/v1/tools/mute-video/run",
        "schema_url": "/api/v1/tools/mute-video",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "engine": {
                  "type": "string",
                  "description": "Processing location",
                  "default": "browser",
                  "enum": [
                    "browser",
                    "server"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/media-tools/mute-video/",
      "agent_url": "https://happytails.ai/agents/en/media-tools/mute-video/"
    },
    {
      "id": "remove-background-noise",
      "category": "media-tools",
      "built": true,
      "requirements": "Denoise speech recordings with strength and original-versus-processed preview; preserve voice character; test hum, traffic, fan noise and speech loss.",
      "implementation": {
        "fields": [
          {
            "key": "strength",
            "label": "Noise reduction (decibels)",
            "value": 12,
            "type": "number",
            "min": 1,
            "max": 40,
            "step": "any"
          },
          {
            "key": "engine",
            "label": "Processing location",
            "type": "select",
            "value": "browser",
            "values": [
              "browser",
              "server"
            ],
            "labels": {
              "browser": "Browser (files stay here)",
              "server": "Local server (larger files)"
            }
          }
        ],
        "files": true,
        "accept": ".mp3,.wav,.m4a,.aac,.flac,.ogg,.opus",
        "multiple": false,
        "input": false,
        "processing": "Browser or server",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Uses FFmpeg spectral noise reduction. Compare the exported audio for speech loss or artefacts.",
        "hybrid": true,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/remove-background-noise/run",
      "api": {
        "id": "remove-background-noise",
        "name": "Remove background noise",
        "category": "media-tools",
        "description": "Reduce steady background noise in an audio recording.",
        "notes": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Uses FFmpeg spectral noise reduction. Compare the exported audio for speech loss or artefacts.",
        "human_path": "/en/media-tools/remove-background-noise/",
        "method": "POST",
        "endpoint": "/api/v1/tools/remove-background-noise/run",
        "schema_url": "/api/v1/tools/remove-background-noise",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "strength": {
                  "type": "number",
                  "description": "Noise reduction (decibels)",
                  "default": 12.0,
                  "minimum": 1,
                  "maximum": 40
                },
                "engine": {
                  "type": "string",
                  "description": "Processing location",
                  "default": "browser",
                  "enum": [
                    "browser",
                    "server"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/media-tools/remove-background-noise/",
      "agent_url": "https://happytails.ai/agents/en/media-tools/remove-background-noise/"
    },
    {
      "id": "remove-silence",
      "category": "media-tools",
      "built": true,
      "requirements": "Detect quiet gaps and preview editable cuts; preserve short natural pauses; export edited audio and cut list; distinguish volume-threshold mode from optional learned speech detection.",
      "implementation": {
        "fields": [
          {
            "key": "threshold",
            "label": "Silence threshold (dB)",
            "value": -40,
            "type": "number",
            "min": -80,
            "max": -10,
            "step": "any"
          },
          {
            "key": "pause",
            "label": "Minimum quiet gap to trim (seconds)",
            "value": 0.5,
            "type": "number",
            "min": 0.1,
            "max": 5,
            "step": "any"
          },
          {
            "key": "engine",
            "label": "Processing location",
            "type": "select",
            "value": "browser",
            "values": [
              "browser",
              "server"
            ],
            "labels": {
              "browser": "Browser (files stay here)",
              "server": "Local server (larger files)"
            }
          }
        ],
        "files": true,
        "accept": ".mp3,.wav,.m4a,.aac,.flac,.ogg,.opus",
        "multiple": false,
        "input": false,
        "processing": "Browser or server",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Uses volume thresholds, not speech recognition. Quiet speech can be affected; listen to the result.",
        "hybrid": true,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/remove-silence/run",
      "api": {
        "id": "remove-silence",
        "name": "Remove silence",
        "category": "media-tools",
        "description": "Remove pauses below your chosen audio threshold.",
        "notes": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Uses volume thresholds, not speech recognition. Quiet speech can be affected; listen to the result.",
        "human_path": "/en/media-tools/remove-silence/",
        "method": "POST",
        "endpoint": "/api/v1/tools/remove-silence/run",
        "schema_url": "/api/v1/tools/remove-silence",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "threshold": {
                  "type": "number",
                  "description": "Silence threshold (dB)",
                  "default": -40.0,
                  "minimum": -80,
                  "maximum": -10
                },
                "pause": {
                  "type": "number",
                  "description": "Minimum quiet gap to trim (seconds)",
                  "default": 0.5,
                  "minimum": 0.1,
                  "maximum": 5
                },
                "engine": {
                  "type": "string",
                  "description": "Processing location",
                  "default": "browser",
                  "enum": [
                    "browser",
                    "server"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/media-tools/remove-silence/",
      "agent_url": "https://happytails.ai/agents/en/media-tools/remove-silence/"
    },
    {
      "id": "resize-video",
      "category": "media-tools",
      "built": true,
      "requirements": "Fit/crop dimensions with codec/pixel constraints; preview output.",
      "implementation": {
        "fields": [
          {
            "key": "width",
            "label": "Width (pixels, even number)",
            "value": 640,
            "type": "number",
            "min": 16,
            "max": 1920,
            "step": 2
          },
          {
            "key": "engine",
            "label": "Processing location",
            "type": "select",
            "value": "browser",
            "values": [
              "browser",
              "server"
            ],
            "labels": {
              "browser": "Browser (files stay here)",
              "server": "Local server (larger files)"
            }
          }
        ],
        "files": true,
        "accept": ".mp4,.mov,.mkv,.webm,.avi",
        "multiple": false,
        "input": false,
        "processing": "Browser or server",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. ",
        "hybrid": true,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/resize-video/run",
      "api": {
        "id": "resize-video",
        "name": "Resize video",
        "category": "media-tools",
        "description": "Resize a video to your chosen width.",
        "notes": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. ",
        "human_path": "/en/media-tools/resize-video/",
        "method": "POST",
        "endpoint": "/api/v1/tools/resize-video/run",
        "schema_url": "/api/v1/tools/resize-video",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "width": {
                  "type": "number",
                  "description": "Width (pixels, even number)",
                  "default": 640.0,
                  "minimum": 16,
                  "maximum": 1920
                },
                "engine": {
                  "type": "string",
                  "description": "Processing location",
                  "default": "browser",
                  "enum": [
                    "browser",
                    "server"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/media-tools/resize-video/",
      "agent_url": "https://happytails.ai/agents/en/media-tools/resize-video/"
    },
    {
      "id": "rotate-video",
      "category": "media-tools",
      "built": true,
      "requirements": "Rotation metadata versus rendered rotation; cross-player verification.",
      "implementation": {
        "fields": [
          {
            "key": "angle",
            "label": "Rotation",
            "value": "90",
            "type": "select",
            "values": [
              "90",
              "180",
              "270"
            ]
          },
          {
            "key": "engine",
            "label": "Processing location",
            "type": "select",
            "value": "browser",
            "values": [
              "browser",
              "server"
            ],
            "labels": {
              "browser": "Browser (files stay here)",
              "server": "Local server (larger files)"
            }
          }
        ],
        "files": true,
        "accept": ".mp4,.mov,.mkv,.webm,.avi",
        "multiple": false,
        "input": false,
        "processing": "Browser or server",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. ",
        "hybrid": true,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/rotate-video/run",
      "api": {
        "id": "rotate-video",
        "name": "Rotate video",
        "category": "media-tools",
        "description": "Rotate a video by 90, 180 or 270 degrees.",
        "notes": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. ",
        "human_path": "/en/media-tools/rotate-video/",
        "method": "POST",
        "endpoint": "/api/v1/tools/rotate-video/run",
        "schema_url": "/api/v1/tools/rotate-video",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "angle": {
                  "type": "string",
                  "description": "Rotation",
                  "default": "90",
                  "enum": [
                    "90",
                    "180",
                    "270"
                  ]
                },
                "engine": {
                  "type": "string",
                  "description": "Processing location",
                  "default": "browser",
                  "enum": [
                    "browser",
                    "server"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/media-tools/rotate-video/",
      "agent_url": "https://happytails.ai/agents/en/media-tools/rotate-video/"
    },
    {
      "id": "screen-recorder",
      "category": "media-tools",
      "built": true,
      "requirements": "User-selected screen capture and audio permissions; device/browser capability checks.",
      "implementation": {
        "fields": [],
        "input": false,
        "note": "Permission is requested only after Start. Captures stay in your browser. Stop ends device access. Browser support and available audio sources vary.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": true
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": false,
        "name": null,
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/media-tools/screen-recorder/",
      "agent_url": "https://happytails.ai/agents/en/media-tools/screen-recorder/"
    },
    {
      "id": "trim-audio",
      "category": "media-tools",
      "built": true,
      "requirements": "Waveform/time inputs, preview, precise boundaries and explicit export format.",
      "implementation": {
        "fields": [
          {
            "key": "start",
            "label": "Start (seconds)",
            "value": 0,
            "type": "number",
            "min": 0,
            "max": 1800,
            "step": "any"
          },
          {
            "key": "end",
            "label": "End (seconds)",
            "value": 1,
            "type": "number",
            "min": 0.01,
            "max": 1800,
            "step": "any"
          },
          {
            "key": "engine",
            "label": "Processing location",
            "type": "select",
            "value": "browser",
            "values": [
              "browser",
              "server"
            ],
            "labels": {
              "browser": "Browser (files stay here)",
              "server": "Local server (larger files)"
            }
          }
        ],
        "files": true,
        "accept": ".mp3,.wav,.m4a,.aac,.flac,.ogg,.opus",
        "multiple": false,
        "input": false,
        "processing": "Browser or server",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. ",
        "hybrid": true,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/trim-audio/run",
      "api": {
        "id": "trim-audio",
        "name": "Trim audio",
        "category": "media-tools",
        "description": "Keep a selected time range from an audio recording.",
        "notes": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. ",
        "human_path": "/en/media-tools/trim-audio/",
        "method": "POST",
        "endpoint": "/api/v1/tools/trim-audio/run",
        "schema_url": "/api/v1/tools/trim-audio",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "start": {
                  "type": "number",
                  "description": "Start (seconds)",
                  "default": 0.0,
                  "minimum": 0,
                  "maximum": 1800
                },
                "end": {
                  "type": "number",
                  "description": "End (seconds)",
                  "default": 1.0,
                  "minimum": 0.01,
                  "maximum": 1800
                },
                "engine": {
                  "type": "string",
                  "description": "Processing location",
                  "default": "browser",
                  "enum": [
                    "browser",
                    "server"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/media-tools/trim-audio/",
      "agent_url": "https://happytails.ai/agents/en/media-tools/trim-audio/"
    },
    {
      "id": "trim-video",
      "category": "media-tools",
      "built": true,
      "requirements": "Preview boundaries and keyframe versus re-encoded cuts; aspect/audio handling.",
      "implementation": {
        "fields": [
          {
            "key": "start",
            "label": "Start (seconds)",
            "value": 0,
            "type": "number",
            "min": 0,
            "max": 1800,
            "step": "any"
          },
          {
            "key": "end",
            "label": "End (seconds)",
            "value": 1,
            "type": "number",
            "min": 0.01,
            "max": 1800,
            "step": "any"
          },
          {
            "key": "engine",
            "label": "Processing location",
            "type": "select",
            "value": "browser",
            "values": [
              "browser",
              "server"
            ],
            "labels": {
              "browser": "Browser (files stay here)",
              "server": "Local server (larger files)"
            }
          }
        ],
        "files": true,
        "accept": ".mp4,.mov,.mkv,.webm,.avi",
        "multiple": false,
        "input": false,
        "processing": "Browser or server",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. ",
        "hybrid": true,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/trim-video/run",
      "api": {
        "id": "trim-video",
        "name": "Trim video",
        "category": "media-tools",
        "description": "Export a selected section of a video.",
        "notes": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. ",
        "human_path": "/en/media-tools/trim-video/",
        "method": "POST",
        "endpoint": "/api/v1/tools/trim-video/run",
        "schema_url": "/api/v1/tools/trim-video",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "start": {
                  "type": "number",
                  "description": "Start (seconds)",
                  "default": 0.0,
                  "minimum": 0,
                  "maximum": 1800
                },
                "end": {
                  "type": "number",
                  "description": "End (seconds)",
                  "default": 1.0,
                  "minimum": 0.01,
                  "maximum": 1800
                },
                "engine": {
                  "type": "string",
                  "description": "Processing location",
                  "default": "browser",
                  "enum": [
                    "browser",
                    "server"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/media-tools/trim-video/",
      "agent_url": "https://happytails.ai/agents/en/media-tools/trim-video/"
    },
    {
      "id": "vocal-remover",
      "category": "media-tools",
      "built": true,
      "requirements": "Separate vocals and instrumental stems from uploaded audio; export both; disclose residual artifacts and test stereo and short clips.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".wav,.mp3,.m4a,.flac,.mp4,.mov,.webm",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "ai": false,
        "maxFileBytes": 20971520,
        "note": "Separate an audio or video clip into vocal and instrumental WAV files using a local Demucs model. Up to 30 seconds and 20 MiB. Processing uses this server, without an external conversion service. Separation is approximate; review both stems.",
        "extra": true,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/vocal-remover/run",
      "api": {
        "id": "vocal-remover",
        "name": "Vocal remover",
        "category": "media-tools",
        "description": "Separate an audio or video clip into vocal and instrumental WAV files using a local Demucs model.",
        "notes": "Separate an audio or video clip into vocal and instrumental WAV files using a local Demucs model. Up to 30 seconds and 20 MiB. Processing uses this server, without an external conversion service. Separation is approximate; review both stems.",
        "human_path": "/en/media-tools/vocal-remover/",
        "method": "POST",
        "endpoint": "/api/v1/tools/vocal-remover/run",
        "schema_url": "/api/v1/tools/vocal-remover",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/media-tools/vocal-remover/",
      "agent_url": "https://happytails.ai/agents/en/media-tools/vocal-remover/"
    },
    {
      "id": "voice-recorder",
      "category": "media-tools",
      "built": true,
      "requirements": "Microphone permission only on action; local preview and explicit recording format.",
      "implementation": {
        "fields": [],
        "input": false,
        "note": "Permission is requested only after Start. Captures stay in your browser. Stop ends device access. Browser support and available audio sources vary.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": true
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": false,
        "name": null,
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/media-tools/voice-recorder/",
      "agent_url": "https://happytails.ai/agents/en/media-tools/voice-recorder/"
    },
    {
      "id": "wav-to-mp3",
      "category": "media-tools",
      "built": true,
      "requirements": "Bitrate/channel/sample-rate controls and preview; explain lossy output.",
      "implementation": {
        "fields": [
          {
            "key": "bitrate",
            "label": "MP3 bitrate (kbps)",
            "value": "128",
            "type": "select",
            "values": [
              "64",
              "96",
              "128",
              "192",
              "256",
              "320"
            ]
          },
          {
            "key": "engine",
            "label": "Processing location",
            "type": "select",
            "value": "browser",
            "values": [
              "browser",
              "server"
            ],
            "labels": {
              "browser": "Browser (files stay here)",
              "server": "Local server (larger files)"
            }
          }
        ],
        "files": true,
        "accept": ".mp3,.wav,.m4a,.aac,.flac,.ogg,.opus",
        "multiple": false,
        "input": false,
        "processing": "Browser or server",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Audio is processed locally with FFmpeg. Lossy conversion does not recover lost detail.",
        "hybrid": true,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/wav-to-mp3/run",
      "api": {
        "id": "wav-to-mp3",
        "name": "WAV to MP3",
        "category": "media-tools",
        "description": "Convert WAV files to MP3 with the available format settings.",
        "notes": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Audio is processed locally with FFmpeg. Lossy conversion does not recover lost detail.",
        "human_path": "/en/media-tools/wav-to-mp3/",
        "method": "POST",
        "endpoint": "/api/v1/tools/wav-to-mp3/run",
        "schema_url": "/api/v1/tools/wav-to-mp3",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "bitrate": {
                  "type": "string",
                  "description": "MP3 bitrate (kbps)",
                  "default": "128",
                  "enum": [
                    "64",
                    "96",
                    "128",
                    "192",
                    "256",
                    "320"
                  ]
                },
                "engine": {
                  "type": "string",
                  "description": "Processing location",
                  "default": "browser",
                  "enum": [
                    "browser",
                    "server"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/media-tools/wav-to-mp3/",
      "agent_url": "https://happytails.ai/agents/en/media-tools/wav-to-mp3/"
    },
    {
      "id": "webm-to-mp4",
      "category": "media-tools",
      "built": true,
      "requirements": "Test codec support, alpha loss and mobile output compatibility.",
      "implementation": {
        "fields": [
          {
            "key": "quality",
            "label": "Quality setting (CRF, lower is sharper)",
            "value": 28,
            "type": "number",
            "min": 18,
            "max": 40,
            "step": 1
          },
          {
            "key": "engine",
            "label": "Processing location",
            "type": "select",
            "value": "browser",
            "values": [
              "browser",
              "server"
            ],
            "labels": {
              "browser": "Browser (files stay here)",
              "server": "Local server (larger files)"
            }
          }
        ],
        "files": true,
        "accept": ".mp4,.mov,.mkv,.webm,.avi",
        "multiple": false,
        "input": false,
        "processing": "Browser or server",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Exports H.264 video and AAC audio in MP4. The first video/audio tracks are used; subtitle and extra tracks are omitted.",
        "hybrid": true,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/webm-to-mp4/run",
      "api": {
        "id": "webm-to-mp4",
        "name": "Webm to MP4",
        "category": "media-tools",
        "description": "Convert WEBM files to MP4 with the available format settings.",
        "notes": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Exports H.264 video and AAC audio in MP4. The first video/audio tracks are used; subtitle and extra tracks are omitted.",
        "human_path": "/en/media-tools/webm-to-mp4/",
        "method": "POST",
        "endpoint": "/api/v1/tools/webm-to-mp4/run",
        "schema_url": "/api/v1/tools/webm-to-mp4",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "quality": {
                  "type": "number",
                  "description": "Quality setting (CRF, lower is sharper)",
                  "default": 28.0,
                  "minimum": 18,
                  "maximum": 40,
                  "multipleOf": 1
                },
                "engine": {
                  "type": "string",
                  "description": "Processing location",
                  "default": "browser",
                  "enum": [
                    "browser",
                    "server"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/media-tools/webm-to-mp4/",
      "agent_url": "https://happytails.ai/agents/en/media-tools/webm-to-mp4/"
    },
    {
      "id": "cidr-to-range",
      "category": "network-tools",
      "built": true,
      "requirements": "First/last addresses, count and IPv6 support without allocating massive address lists.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": true,
          "label": "Network in CIDR notation",
          "placeholder": "192.0.2.0/24",
          "help": "Enter an IP address followed by a slash and prefix length. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/cidr-to-range/run",
      "api": {
        "id": "cidr-to-range",
        "name": "CIDR to range",
        "category": "network-tools",
        "description": "First/last addresses, count and IPv6 support without allocating massive address lists.",
        "notes": "",
        "human_path": "/en/network-tools/cidr-to-range/",
        "method": "POST",
        "endpoint": "/api/v1/tools/cidr-to-range/run",
        "schema_url": "/api/v1/tools/cidr-to-range",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/network-tools/cidr-to-range/",
      "agent_url": "https://happytails.ai/agents/en/network-tools/cidr-to-range/"
    },
    {
      "id": "dns-lookup",
      "category": "network-tools",
      "built": true,
      "requirements": "A AAAA MX TXT CNAME NS SOA records with resolver and time; distinguish authoritative and cached answers.",
      "implementation": {
        "fields": [
          {
            "key": "record",
            "label": "Record type",
            "value": "A",
            "type": "select",
            "values": [
              "A",
              "AAAA",
              "MX",
              "TXT",
              "NS",
              "CNAME",
              "SOA"
            ]
          }
        ],
        "processing": "Server required",
        "note": "Uses the local diagnostic server to contact the supplied public host or DNS/RDAP provider. Only public internet addresses are permitted; requests time out and redirects are bounded.",
        "experience": {
          "automatic": false,
          "single": true,
          "label": "Domain name",
          "placeholder": "happytails.ai",
          "help": "Enter one domain name without https://, a path or a port.",
          "action": "Check domain"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/dns-lookup/run",
      "api": {
        "id": "dns-lookup",
        "name": "DNS lookup",
        "category": "network-tools",
        "description": "A AAAA MX TXT CNAME NS SOA records with resolver and time.",
        "notes": "Uses the local diagnostic server to contact the supplied public host or DNS/RDAP provider. Only public internet addresses are permitted; requests time out and redirects are bounded.",
        "human_path": "/en/network-tools/dns-lookup/",
        "method": "POST",
        "endpoint": "/api/v1/tools/dns-lookup/run",
        "schema_url": "/api/v1/tools/dns-lookup",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "record": {
                  "type": "string",
                  "description": "Record type",
                  "default": "A",
                  "enum": [
                    "A",
                    "AAAA",
                    "MX",
                    "TXT",
                    "NS",
                    "CNAME",
                    "SOA"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; contacts public network services",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": null
        }
      },
      "agent_processing": "Server; contacts public network services",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/network-tools/dns-lookup/",
      "agent_url": "https://happytails.ai/agents/en/network-tools/dns-lookup/"
    },
    {
      "id": "dns-propagation",
      "category": "network-tools",
      "built": false,
      "requirements": "Real geographically distributed resolvers and timestamps; show failures and location coverage.",
      "implementation": {},
      "execution": "Not connected",
      "api": null,
      "browser_agent": {
        "supported": false,
        "name": null,
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/network-tools/dns-propagation/",
      "agent_url": "https://happytails.ai/agents/en/network-tools/dns-propagation/"
    },
    {
      "id": "ip-lookup",
      "category": "network-tools",
      "built": true,
      "requirements": "ASN, approximate geography and data timestamp; no street-address precision claim.",
      "implementation": {
        "fields": [],
        "processing": "Server required",
        "note": "Uses the local diagnostic server to contact the supplied public host or DNS/RDAP provider. Only public internet addresses are permitted; requests time out and redirects are bounded.",
        "experience": {
          "automatic": false,
          "single": true,
          "label": "IP address",
          "placeholder": "8.8.8.8",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/ip-lookup/run",
      "api": {
        "id": "ip-lookup",
        "name": "IP lookup",
        "category": "network-tools",
        "description": "ASN, approximate geography and data timestamp.",
        "notes": "Uses the local diagnostic server to contact the supplied public host or DNS/RDAP provider. Only public internet addresses are permitted; requests time out and redirects are bounded.",
        "human_path": "/en/network-tools/ip-lookup/",
        "method": "POST",
        "endpoint": "/api/v1/tools/ip-lookup/run",
        "schema_url": "/api/v1/tools/ip-lookup",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; contacts public network services",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": null
        }
      },
      "agent_processing": "Server; contacts public network services",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/network-tools/ip-lookup/",
      "agent_url": "https://happytails.ai/agents/en/network-tools/ip-lookup/"
    },
    {
      "id": "ip-range-to-cidr",
      "category": "network-tools",
      "built": true,
      "requirements": "Minimal exact covering blocks; validate ordering and address family.",
      "implementation": {
        "fields": [
          {
            "key": "end",
            "label": "Ending IP address",
            "value": "192.168.1.255",
            "type": "text"
          }
        ],
        "experience": {
          "automatic": true,
          "single": true,
          "label": "Starting IP address",
          "placeholder": "192.168.1.0",
          "help": "Enter the first address here and the last address in Ending IP address below. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/ip-range-to-cidr/run",
      "api": {
        "id": "ip-range-to-cidr",
        "name": "IP range to CIDR",
        "category": "network-tools",
        "description": "Minimal exact covering blocks.",
        "notes": "",
        "human_path": "/en/network-tools/ip-range-to-cidr/",
        "method": "POST",
        "endpoint": "/api/v1/tools/ip-range-to-cidr/run",
        "schema_url": "/api/v1/tools/ip-range-to-cidr",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "end": {
                  "type": "string",
                  "description": "Ending IP address",
                  "default": "192.168.1.255"
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/network-tools/ip-range-to-cidr/",
      "agent_url": "https://happytails.ai/agents/en/network-tools/ip-range-to-cidr/"
    },
    {
      "id": "ipv6-compress",
      "category": "network-tools",
      "built": true,
      "requirements": "Compress/expand canonical IPv6 with round-trip checks.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": true,
          "label": "IPv6 address",
          "placeholder": "2001:0db8:0000:0000:0000:0000:0000:0001",
          "help": "Enter one IPv6 address. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/ipv6-compress/run",
      "api": {
        "id": "ipv6-compress",
        "name": "Ipv6 compress",
        "category": "network-tools",
        "description": "Compress/expand canonical IPv6 with round-trip checks.",
        "notes": "",
        "human_path": "/en/network-tools/ipv6-compress/",
        "method": "POST",
        "endpoint": "/api/v1/tools/ipv6-compress/run",
        "schema_url": "/api/v1/tools/ipv6-compress",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/network-tools/ipv6-compress/",
      "agent_url": "https://happytails.ai/agents/en/network-tools/ipv6-compress/"
    },
    {
      "id": "reverse-dns",
      "category": "network-tools",
      "built": true,
      "requirements": "PTR query results and missing-record states; do not infer ownership.",
      "implementation": {
        "fields": [],
        "processing": "Server required",
        "note": "Uses the local diagnostic server to contact the supplied public host or DNS/RDAP provider. Only public internet addresses are permitted; requests time out and redirects are bounded.",
        "experience": {
          "automatic": false,
          "single": true,
          "label": "IP address",
          "placeholder": "8.8.8.8",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/reverse-dns/run",
      "api": {
        "id": "reverse-dns",
        "name": "Reverse DNS",
        "category": "network-tools",
        "description": "PTR query results and missing-record states.",
        "notes": "Uses the local diagnostic server to contact the supplied public host or DNS/RDAP provider. Only public internet addresses are permitted; requests time out and redirects are bounded.",
        "human_path": "/en/network-tools/reverse-dns/",
        "method": "POST",
        "endpoint": "/api/v1/tools/reverse-dns/run",
        "schema_url": "/api/v1/tools/reverse-dns",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; contacts public network services",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": null
        }
      },
      "agent_processing": "Server; contacts public network services",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/network-tools/reverse-dns/",
      "agent_url": "https://happytails.ai/agents/en/network-tools/reverse-dns/"
    },
    {
      "id": "subnet-calculator",
      "category": "network-tools",
      "built": true,
      "requirements": "IPv4/IPv6 ranges, prefix length and usable-address conventions; exact integer arithmetic.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": true,
          "label": "Network in CIDR notation",
          "placeholder": "192.0.2.0/24",
          "help": "Enter an IP address followed by a slash and prefix length. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/subnet-calculator/run",
      "api": {
        "id": "subnet-calculator",
        "name": "Subnet calculator",
        "category": "network-tools",
        "description": "IPv4/IPv6 ranges, prefix length and usable-address conventions.",
        "notes": "",
        "human_path": "/en/network-tools/subnet-calculator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/subnet-calculator/run",
        "schema_url": "/api/v1/tools/subnet-calculator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/network-tools/subnet-calculator/",
      "agent_url": "https://happytails.ai/agents/en/network-tools/subnet-calculator/"
    },
    {
      "id": "what-is-my-ip",
      "category": "network-tools",
      "built": true,
      "requirements": "Display public IPv4/IPv6 observed by endpoint; explain VPN and proxy effects; never call it device identity.",
      "implementation": {
        "fields": [],
        "input": false,
        "processing": "Client-side",
        "note": "Contacts ipify directly from your browser after Run. The provider observes your public IP; this does not reveal your private LAN address.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/network-tools/what-is-my-ip/",
      "agent_url": "https://happytails.ai/agents/en/network-tools/what-is-my-ip/"
    },
    {
      "id": "whois-lookup",
      "category": "network-tools",
      "built": true,
      "requirements": "RDAP-first registration lookup with redaction and registry-specific availability.",
      "implementation": {
        "fields": [],
        "processing": "Server required",
        "note": "Uses the local diagnostic server to contact the supplied public host or DNS/RDAP provider. Only public internet addresses are permitted; requests time out and redirects are bounded.",
        "experience": {
          "automatic": false,
          "single": true,
          "label": "Domain name",
          "placeholder": "happytails.ai",
          "help": "Enter one domain name without https://, a path or a port.",
          "action": "Check domain"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/whois-lookup/run",
      "api": {
        "id": "whois-lookup",
        "name": "Whois lookup",
        "category": "network-tools",
        "description": "RDAP-first registration lookup with redaction and registry-specific availability.",
        "notes": "Uses the local diagnostic server to contact the supplied public host or DNS/RDAP provider. Only public internet addresses are permitted; requests time out and redirects are bounded.",
        "human_path": "/en/network-tools/whois-lookup/",
        "method": "POST",
        "endpoint": "/api/v1/tools/whois-lookup/run",
        "schema_url": "/api/v1/tools/whois-lookup",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; contacts public network services",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": null
        }
      },
      "agent_processing": "Server; contacts public network services",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/network-tools/whois-lookup/",
      "agent_url": "https://happytails.ai/agents/en/network-tools/whois-lookup/"
    },
    {
      "id": "add-page-numbers",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Position, start value, page ranges and margins; avoid overlapping existing content.",
      "implementation": {
        "fields": [
          {
            "key": "pages",
            "label": "Pages (blank = all)",
            "value": "",
            "type": "text"
          }
        ],
        "files": true,
        "multiple": false,
        "input": false,
        "accept": ".pdf",
        "note": "Page numbers start at 1. Password-encrypted PDFs must be unlocked first.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/add-page-numbers/run",
      "api": {
        "id": "add-page-numbers",
        "name": "Add page numbers",
        "category": "pdf-tools",
        "description": "Add page numbers to a PDF.",
        "notes": "Page numbers start at 1. Password-encrypted PDFs must be unlocked first.",
        "human_path": "/en/pdf-tools/add-page-numbers/",
        "method": "POST",
        "endpoint": "/api/v1/tools/add-page-numbers/run",
        "schema_url": "/api/v1/tools/add-page-numbers",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "pages": {
                  "type": "string",
                  "description": "Pages (blank = all)",
                  "default": ""
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/add-page-numbers/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/add-page-numbers/"
    },
    {
      "id": "alternate-merge-pdf",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Exactly two PDFs; optionally reverse second document; append unmatched pages; keep text selectable.",
      "implementation": {
        "fields": [
          {
            "key": "reverse",
            "label": "Reverse the second PDF (back scans)",
            "value": false,
            "type": "checkbox"
          }
        ],
        "files": true,
        "input": false,
        "multiple": true,
        "accept": ".pdf",
        "note": "Runs on your device. Up to 100 pages per input. Choose front scans first, back scans second. Extra pages are appended in order.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/alternate-merge-pdf/run",
      "api": {
        "id": "alternate-merge-pdf",
        "name": "Alternate merge PDF",
        "category": "pdf-tools",
        "description": "Combine front and back scans in alternating order.",
        "notes": "Runs on your device. Up to 100 pages per input. Choose front scans first, back scans second. Extra pages are appended in order.",
        "human_path": "/en/pdf-tools/alternate-merge-pdf/",
        "method": "POST",
        "endpoint": "/api/v1/tools/alternate-merge-pdf/run",
        "schema_url": "/api/v1/tools/alternate-merge-pdf",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "reverse": {
                  "type": "boolean",
                  "description": "Reverse the second PDF (back scans)",
                  "default": false
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 20,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 20,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/alternate-merge-pdf/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/alternate-merge-pdf/"
    },
    {
      "id": "annotate-pdf",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Text, drawing, highlights and output persistence; distinguish annotation from editing existing text.",
      "implementation": {
        "fields": [
          {
            "key": "page",
            "label": "Page",
            "value": 1,
            "type": "number"
          },
          {
            "key": "x",
            "label": "X from left (points)",
            "value": 40,
            "type": "number"
          },
          {
            "key": "y",
            "label": "Y from bottom (points)",
            "value": 40,
            "type": "number"
          },
          {
            "key": "size",
            "label": "Text size",
            "value": 12,
            "type": "number"
          }
        ],
        "files": true,
        "accept": ".pdf",
        "note": "Adds visible text to a page. Coordinates are PDF points; this is not secure redaction or a digital signature.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/annotate-pdf/run",
      "api": {
        "id": "annotate-pdf",
        "name": "Annotate PDF",
        "category": "pdf-tools",
        "description": "Add visible text to a PDF page.",
        "notes": "Adds visible text to a page. Coordinates are PDF points; this is not secure redaction or a digital signature.",
        "human_path": "/en/pdf-tools/annotate-pdf/",
        "method": "POST",
        "endpoint": "/api/v1/tools/annotate-pdf/run",
        "schema_url": "/api/v1/tools/annotate-pdf",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "page": {
                  "type": "number",
                  "description": "Page",
                  "default": 1.0
                },
                "x": {
                  "type": "number",
                  "description": "X from left (points)",
                  "default": 40.0
                },
                "y": {
                  "type": "number",
                  "description": "Y from bottom (points)",
                  "default": 40.0
                },
                "size": {
                  "type": "number",
                  "description": "Text size",
                  "default": 12.0
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/annotate-pdf/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/annotate-pdf/"
    },
    {
      "id": "bates-number-pdf",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Prefix, starting number and digit padding; visible footer with selectable text; reject labels that will not fit.",
      "implementation": {
        "fields": [
          {
            "key": "prefix",
            "label": "Reference prefix",
            "value": "DOC-",
            "type": "text"
          },
          {
            "key": "start",
            "label": "Starting number",
            "value": 1,
            "type": "number",
            "min": 0,
            "max": 999999999,
            "step": 1
          },
          {
            "key": "digits",
            "label": "Minimum number of digits",
            "value": 6,
            "type": "number",
            "min": 1,
            "max": 12,
            "step": 1
          }
        ],
        "files": true,
        "input": false,
        "multiple": false,
        "accept": ".pdf",
        "note": "Runs on your device. Up to 100 pages per input. Labels may overlap existing content in the top or bottom margin. Supports unrotated pages and basic Latin text.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/bates-number-pdf/run",
      "api": {
        "id": "bates-number-pdf",
        "name": "Bates number PDF",
        "category": "pdf-tools",
        "description": "Add a unique reference number to every PDF page.",
        "notes": "Runs on your device. Up to 100 pages per input. Labels may overlap existing content in the top or bottom margin. Supports unrotated pages and basic Latin text.",
        "human_path": "/en/pdf-tools/bates-number-pdf/",
        "method": "POST",
        "endpoint": "/api/v1/tools/bates-number-pdf/run",
        "schema_url": "/api/v1/tools/bates-number-pdf",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "prefix": {
                  "type": "string",
                  "description": "Reference prefix",
                  "default": "DOC-"
                },
                "start": {
                  "type": "number",
                  "description": "Starting number",
                  "default": 1.0,
                  "minimum": 0,
                  "maximum": 999999999,
                  "multipleOf": 1
                },
                "digits": {
                  "type": "number",
                  "description": "Minimum number of digits",
                  "default": 6.0,
                  "minimum": 1,
                  "maximum": 12,
                  "multipleOf": 1
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/bates-number-pdf/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/bates-number-pdf/"
    },
    {
      "id": "compare-pdf",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Separate visual and text differences; report reading-order limitations.",
      "implementation": {
        "fields": [],
        "files": true,
        "multiple": true,
        "input": false,
        "accept": ".pdf",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/compare-pdf/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/compare-pdf/"
    },
    {
      "id": "compress-pdf",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Report size savings and visual loss; preserve selectable text where promised; handle already optimized files.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".pdf",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Processed by the local, self-hosted engine. No third-party conversion service is used. Lossless structural optimisation and supported structural recovery. No image downsampling or guarantee of smaller output.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/compress-pdf/run",
      "api": {
        "id": "compress-pdf",
        "name": "Compress PDF",
        "category": "pdf-tools",
        "description": "Rewrite PDF objects and streams to reduce avoidable file overhead.",
        "notes": "Processed by the local, self-hosted engine. No third-party conversion service is used. Lossless structural optimisation and supported structural recovery. No image downsampling or guarantee of smaller output.",
        "human_path": "/en/pdf-tools/compress-pdf/",
        "method": "POST",
        "endpoint": "/api/v1/tools/compress-pdf/run",
        "schema_url": "/api/v1/tools/compress-pdf",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/compress-pdf/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/compress-pdf/"
    },
    {
      "id": "create-pdf-form",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Add typed fields, tab order and accessibility; cross-reader compatibility tests.",
      "implementation": {
        "fields": [],
        "note": "Creates a fillable text-field form. Input example: [{\"name\":\"email\",\"label\":\"Email address\"}].",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/create-pdf-form/run",
      "api": {
        "id": "create-pdf-form",
        "name": "Create PDF form",
        "category": "pdf-tools",
        "description": "Create a PDF with fillable text fields.",
        "notes": "Creates a fillable text-field form. Input example: [{\"name\":\"email\",\"label\":\"Email address\"}].",
        "human_path": "/en/pdf-tools/create-pdf-form/",
        "method": "POST",
        "endpoint": "/api/v1/tools/create-pdf-form/run",
        "schema_url": "/api/v1/tools/create-pdf-form",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/create-pdf-form/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/create-pdf-form/"
    },
    {
      "id": "crop-pdf",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Page boxes and margins; explain cropping may leave hidden content rather than redact it.",
      "implementation": {
        "fields": [
          {
            "key": "pages",
            "label": "Pages (blank = all)",
            "value": "",
            "type": "text"
          },
          {
            "key": "margin",
            "label": "Crop margin (PDF points)",
            "value": 36,
            "type": "number"
          }
        ],
        "files": true,
        "multiple": false,
        "input": false,
        "accept": ".pdf",
        "note": "Cropping changes the visible area, not the underlying content. It is not redaction.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/crop-pdf/run",
      "api": {
        "id": "crop-pdf",
        "name": "Crop PDF",
        "category": "pdf-tools",
        "description": "Change the visible margins of selected PDF pages.",
        "notes": "Cropping changes the visible area, not the underlying content. It is not redaction.",
        "human_path": "/en/pdf-tools/crop-pdf/",
        "method": "POST",
        "endpoint": "/api/v1/tools/crop-pdf/run",
        "schema_url": "/api/v1/tools/crop-pdf",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "pages": {
                  "type": "string",
                  "description": "Pages (blank = all)",
                  "default": ""
                },
                "margin": {
                  "type": "number",
                  "description": "Crop margin (PDF points)",
                  "default": 36.0
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/crop-pdf/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/crop-pdf/"
    },
    {
      "id": "delete-pages",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Delete selected pages with preview; handle empty-document outcome; leave original untouched.",
      "implementation": {
        "fields": [
          {
            "key": "pages",
            "label": "Pages (blank = all)",
            "value": "",
            "type": "text"
          }
        ],
        "files": true,
        "multiple": false,
        "input": false,
        "accept": ".pdf",
        "note": "Page numbers start at 1. Password-encrypted PDFs must be unlocked first.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/delete-pages/run",
      "api": {
        "id": "delete-pages",
        "name": "Delete pages",
        "category": "pdf-tools",
        "description": "Remove selected pages from a PDF copy.",
        "notes": "Page numbers start at 1. Password-encrypted PDFs must be unlocked first.",
        "human_path": "/en/pdf-tools/delete-pages/",
        "method": "POST",
        "endpoint": "/api/v1/tools/delete-pages/run",
        "schema_url": "/api/v1/tools/delete-pages",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "pages": {
                  "type": "string",
                  "description": "Pages (blank = all)",
                  "default": ""
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/delete-pages/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/delete-pages/"
    },
    {
      "id": "extract-pages",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Export a selected page subset to one PDF; clearly separate from multiple-file splitting.",
      "implementation": {
        "fields": [
          {
            "key": "pages",
            "label": "Pages (blank = all)",
            "value": "",
            "type": "text"
          }
        ],
        "files": true,
        "multiple": false,
        "input": false,
        "accept": ".pdf",
        "note": "Page numbers start at 1. Password-encrypted PDFs must be unlocked first.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/extract-pages/run",
      "api": {
        "id": "extract-pages",
        "name": "Extract pages",
        "category": "pdf-tools",
        "description": "Create a PDF containing the pages you select.",
        "notes": "Page numbers start at 1. Password-encrypted PDFs must be unlocked first.",
        "human_path": "/en/pdf-tools/extract-pages/",
        "method": "POST",
        "endpoint": "/api/v1/tools/extract-pages/run",
        "schema_url": "/api/v1/tools/extract-pages",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "pages": {
                  "type": "string",
                  "description": "Pages (blank = all)",
                  "default": ""
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/extract-pages/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/extract-pages/"
    },
    {
      "id": "extract-pdf-images",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Extract embedded images rather than render full pages; preserve actual resolutions.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".pdf",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Processed by the local, self-hosted engine. No third-party conversion service is used. Extracts embedded raster images at their original resolution, with soft masks applied when supported. Does not render whole pages.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/extract-pdf-images/run",
      "api": {
        "id": "extract-pdf-images",
        "name": "Extract PDF images",
        "category": "pdf-tools",
        "description": "Extract embedded raster images from a PDF into a ZIP.",
        "notes": "Processed by the local, self-hosted engine. No third-party conversion service is used. Extracts embedded raster images at their original resolution, with soft masks applied when supported. Does not render whole pages.",
        "human_path": "/en/pdf-tools/extract-pdf-images/",
        "method": "POST",
        "endpoint": "/api/v1/tools/extract-pdf-images/run",
        "schema_url": "/api/v1/tools/extract-pdf-images",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/extract-pdf-images/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/extract-pdf-images/"
    },
    {
      "id": "fill-pdf",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Fill supported AcroForms; detect unsupported XFA; test field appearance.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".pdf",
        "note": "Run with blank input to list field names. Then enter a JSON object mapping field names to values. Supports text, checkbox and choice fields.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/fill-pdf/run",
      "api": {
        "id": "fill-pdf",
        "name": "Fill PDF",
        "category": "pdf-tools",
        "description": "Fill existing PDF form fields with values you provide.",
        "notes": "Run with blank input to list field names. Then enter a JSON object mapping field names to values. Supports text, checkbox and choice fields.",
        "human_path": "/en/pdf-tools/fill-pdf/",
        "method": "POST",
        "endpoint": "/api/v1/tools/fill-pdf/run",
        "schema_url": "/api/v1/tools/fill-pdf",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/fill-pdf/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/fill-pdf/"
    },
    {
      "id": "flatten-pdf",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Flatten form fields/annotations deliberately; explain loss of editability.",
      "implementation": {
        "fields": [],
        "files": true,
        "multiple": false,
        "input": false,
        "accept": ".pdf",
        "note": "Page numbers start at 1. Password-encrypted PDFs must be unlocked first.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/flatten-pdf/run",
      "api": {
        "id": "flatten-pdf",
        "name": "Flatten PDF",
        "category": "pdf-tools",
        "description": "Make filled PDF form values part of the page content.",
        "notes": "Page numbers start at 1. Password-encrypted PDFs must be unlocked first.",
        "human_path": "/en/pdf-tools/flatten-pdf/",
        "method": "POST",
        "endpoint": "/api/v1/tools/flatten-pdf/run",
        "schema_url": "/api/v1/tools/flatten-pdf",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/flatten-pdf/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/flatten-pdf/"
    },
    {
      "id": "heic-to-pdf",
      "category": "pdf-tools",
      "built": true,
      "requirements": "HEIC orientation/color plus PDF paper and margin controls.",
      "implementation": {
        "fields": [
          {
            "key": "quality",
            "label": "Quality (%)",
            "value": 85,
            "type": "number",
            "min": 1,
            "max": 100,
            "step": 1
          }
        ],
        "files": true,
        "accept": ".heic,.heif",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Processed by the local, self-hosted engine. No third-party conversion service is used. Converts the primary HEIC image with orientation applied. Multi-image sequences and HDR preservation are not supported.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/heic-to-pdf/run",
      "api": {
        "id": "heic-to-pdf",
        "name": "HEIC to PDF",
        "category": "pdf-tools",
        "description": "Convert HEIC files to PDF with the available format settings.",
        "notes": "Processed by the local, self-hosted engine. No third-party conversion service is used. Converts the primary HEIC image with orientation applied. Multi-image sequences and HDR preservation are not supported.",
        "human_path": "/en/pdf-tools/heic-to-pdf/",
        "method": "POST",
        "endpoint": "/api/v1/tools/heic-to-pdf/run",
        "schema_url": "/api/v1/tools/heic-to-pdf",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "quality": {
                  "type": "number",
                  "description": "Quality (%)",
                  "default": 85.0,
                  "minimum": 1,
                  "maximum": 100,
                  "multipleOf": 1
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/heic-to-pdf/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/heic-to-pdf/"
    },
    {
      "id": "jpg-to-pdf",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Page dimensions, margins, orientation and input order; handle EXIF orientation.",
      "implementation": {
        "fields": [],
        "files": true,
        "multiple": true,
        "input": false,
        "accept": "image/*,.svg",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/jpg-to-pdf/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/jpg-to-pdf/"
    },
    {
      "id": "merge-pdf",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Reorder input documents and pages; preserve page dimensions; report encrypted/unsupported files.",
      "implementation": {
        "fields": [],
        "files": true,
        "multiple": true,
        "input": false,
        "accept": ".pdf",
        "note": "Page numbers start at 1. Password-encrypted PDFs must be unlocked first.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/merge-pdf/run",
      "api": {
        "id": "merge-pdf",
        "name": "Merge PDF",
        "category": "pdf-tools",
        "description": "Combine PDF files into one document.",
        "notes": "Page numbers start at 1. Password-encrypted PDFs must be unlocked first.",
        "human_path": "/en/pdf-tools/merge-pdf/",
        "method": "POST",
        "endpoint": "/api/v1/tools/merge-pdf/run",
        "schema_url": "/api/v1/tools/merge-pdf",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 20,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 20,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/merge-pdf/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/merge-pdf/"
    },
    {
      "id": "ocr-pdf",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Scanned pages, language selection and searchable text layer; measure recognition errors.",
      "implementation": {
        "fields": [
          {
            "key": "language",
            "label": "OCR language",
            "value": "eng",
            "type": "select",
            "values": [
              "eng"
            ]
          }
        ],
        "files": true,
        "accept": ".pdf",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Processed by the local, self-hosted engine. No third-party conversion service is used. Creates a searchable PDF from rendered pages. Original vector content and forms are flattened. Up to 30 pages; review recognised text.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/ocr-pdf/run",
      "api": {
        "id": "ocr-pdf",
        "name": "OCR PDF",
        "category": "pdf-tools",
        "description": "Add searchable English text to scanned PDF pages.",
        "notes": "Processed by the local, self-hosted engine. No third-party conversion service is used. Creates a searchable PDF from rendered pages. Original vector content and forms are flattened. Up to 30 pages; review recognised text.",
        "human_path": "/en/pdf-tools/ocr-pdf/",
        "method": "POST",
        "endpoint": "/api/v1/tools/ocr-pdf/run",
        "schema_url": "/api/v1/tools/ocr-pdf",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "language": {
                  "type": "string",
                  "description": "OCR language",
                  "default": "eng",
                  "enum": [
                    "eng"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/ocr-pdf/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/ocr-pdf/"
    },
    {
      "id": "pages-per-sheet",
      "category": "pdf-tools",
      "built": true,
      "requirements": "N-up layout with paper size, margins and reading order preview.",
      "implementation": {
        "fields": [
          {
            "key": "columns",
            "label": "Columns",
            "value": 2,
            "type": "number"
          },
          {
            "key": "rows",
            "label": "Rows",
            "value": 1,
            "type": "number"
          }
        ],
        "files": true,
        "input": false,
        "accept": ".pdf",
        "note": "Fits pages onto landscape A4 sheets. Existing page content is preserved as embedded PDF pages.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/pages-per-sheet/run",
      "api": {
        "id": "pages-per-sheet",
        "name": "Pages per sheet",
        "category": "pdf-tools",
        "description": "Place several PDF pages on each output sheet.",
        "notes": "Fits pages onto landscape A4 sheets. Existing page content is preserved as embedded PDF pages.",
        "human_path": "/en/pdf-tools/pages-per-sheet/",
        "method": "POST",
        "endpoint": "/api/v1/tools/pages-per-sheet/run",
        "schema_url": "/api/v1/tools/pages-per-sheet",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "columns": {
                  "type": "number",
                  "description": "Columns",
                  "default": 2.0
                },
                "rows": {
                  "type": "number",
                  "description": "Rows",
                  "default": 1.0
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/pages-per-sheet/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/pages-per-sheet/"
    },
    {
      "id": "pdf-header-footer",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Support {page} and {pages}; selectable text; printable basic Latin; warn about existing content in page margins.",
      "implementation": {
        "fields": [
          {
            "key": "header",
            "label": "Header text",
            "value": "",
            "type": "text"
          },
          {
            "key": "footer",
            "label": "Footer text",
            "value": "Page {page} of {pages}",
            "type": "text"
          }
        ],
        "files": true,
        "input": false,
        "multiple": false,
        "accept": ".pdf",
        "note": "Runs on your device. Up to 100 pages per input. Labels may overlap existing content in the top or bottom margin. Supports unrotated pages and basic Latin text.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/pdf-header-footer/run",
      "api": {
        "id": "pdf-header-footer",
        "name": "PDF header footer",
        "category": "pdf-tools",
        "description": "Add a header and footer to every PDF page.",
        "notes": "Runs on your device. Up to 100 pages per input. Labels may overlap existing content in the top or bottom margin. Supports unrotated pages and basic Latin text.",
        "human_path": "/en/pdf-tools/pdf-header-footer/",
        "method": "POST",
        "endpoint": "/api/v1/tools/pdf-header-footer/run",
        "schema_url": "/api/v1/tools/pdf-header-footer",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "header": {
                  "type": "string",
                  "description": "Header text",
                  "default": ""
                },
                "footer": {
                  "type": "string",
                  "description": "Footer text",
                  "default": "Page {page} of {pages}"
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/pdf-header-footer/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/pdf-header-footer/"
    },
    {
      "id": "pdf-to-excel",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Detect table boundaries and preserve cell structure; scanned tables need OCR.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".pdf",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Processed by the local, self-hosted engine. No third-party conversion service is used. Exports detected tables to separate worksheets. Inspect merged cells and reading order. Scans need OCR first.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/pdf-to-excel/run",
      "api": {
        "id": "pdf-to-excel",
        "name": "PDF to excel",
        "category": "pdf-tools",
        "description": "Extract detected PDF tables into an Excel workbook.",
        "notes": "Processed by the local, self-hosted engine. No third-party conversion service is used. Exports detected tables to separate worksheets. Inspect merged cells and reading order. Scans need OCR first.",
        "human_path": "/en/pdf-tools/pdf-to-excel/",
        "method": "POST",
        "endpoint": "/api/v1/tools/pdf-to-excel/run",
        "schema_url": "/api/v1/tools/pdf-to-excel",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/pdf-to-excel/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/pdf-to-excel/"
    },
    {
      "id": "pdf-to-jpg",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Rasterize selected pages at defined resolution; separate rendering from embedded-image extraction.",
      "implementation": {
        "fields": [
          {
            "key": "pages",
            "label": "Pages (blank = all)",
            "value": "",
            "type": "text"
          },
          {
            "key": "scale",
            "label": "Image render scale",
            "value": 1.5,
            "type": "number"
          }
        ],
        "files": true,
        "input": false,
        "accept": ".pdf",
        "note": "Text extraction requires selectable text; scanned pages need OCR. Markdown export contains extracted paragraphs, not reconstructed tables or heading semantics.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/pdf-to-jpg/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/pdf-to-jpg/"
    },
    {
      "id": "pdf-to-markdown",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Headings, tables and reading order require fidelity tests; distinguish text extraction from OCR.",
      "implementation": {
        "fields": [
          {
            "key": "pages",
            "label": "Pages (blank = all)",
            "value": "",
            "type": "text"
          }
        ],
        "files": true,
        "input": false,
        "accept": ".pdf",
        "note": "Text extraction requires selectable text; scanned pages need OCR. Markdown export contains extracted paragraphs, not reconstructed tables or heading semantics.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/pdf-to-markdown/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/pdf-to-markdown/"
    },
    {
      "id": "pdf-to-pdfa",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Select supported conformance level and validate with a real PDF/A checker.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".pdf",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Convert a PDF to PDF/A-2b using local Ghostscript and verify conformance with veraPDF before download. Up to 100 pages and 20 MiB. Review page appearance. Files are processed on this server.",
        "extra": true,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/pdf-to-pdfa/run",
      "api": {
        "id": "pdf-to-pdfa",
        "name": "PDF to pdfa",
        "category": "pdf-tools",
        "description": "Convert a PDF to PDF/A-2b using local Ghostscript and verify conformance with veraPDF before download.",
        "notes": "Convert a PDF to PDF/A-2b using local Ghostscript and verify conformance with veraPDF before download. Up to 100 pages and 20 MiB. Review page appearance. Files are processed on this server.",
        "human_path": "/en/pdf-tools/pdf-to-pdfa/",
        "method": "POST",
        "endpoint": "/api/v1/tools/pdf-to-pdfa/run",
        "schema_url": "/api/v1/tools/pdf-to-pdfa",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/pdf-to-pdfa/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/pdf-to-pdfa/"
    },
    {
      "id": "pdf-to-png",
      "category": "pdf-tools",
      "built": true,
      "requirements": "PNG page rendering with resolution and transparency behavior; batch naming and ZIP output.",
      "implementation": {
        "fields": [
          {
            "key": "pages",
            "label": "Pages (blank = all)",
            "value": "",
            "type": "text"
          },
          {
            "key": "scale",
            "label": "Image render scale",
            "value": 1.5,
            "type": "number"
          }
        ],
        "files": true,
        "input": false,
        "accept": ".pdf",
        "note": "Text extraction requires selectable text; scanned pages need OCR. Markdown export contains extracted paragraphs, not reconstructed tables or heading semantics.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/pdf-to-png/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/pdf-to-png/"
    },
    {
      "id": "pdf-to-powerpoint",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Disclose whether slides contain editable objects or rendered page images.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".pdf",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Processed by the local, self-hosted engine. No third-party conversion service is used. Creates one slide per page using a rendered image. Slide contents are not individually editable.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/pdf-to-powerpoint/run",
      "api": {
        "id": "pdf-to-powerpoint",
        "name": "PDF to powerpoint",
        "category": "pdf-tools",
        "description": "Turn PDF pages into image-based PowerPoint slides.",
        "notes": "Processed by the local, self-hosted engine. No third-party conversion service is used. Creates one slide per page using a rendered image. Slide contents are not individually editable.",
        "human_path": "/en/pdf-tools/pdf-to-powerpoint/",
        "method": "POST",
        "endpoint": "/api/v1/tools/pdf-to-powerpoint/run",
        "schema_url": "/api/v1/tools/pdf-to-powerpoint",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/pdf-to-powerpoint/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/pdf-to-powerpoint/"
    },
    {
      "id": "pdf-to-text",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Text PDFs only initially; preserve reading order as best effort; detect scanned-only pages.",
      "implementation": {
        "fields": [
          {
            "key": "pages",
            "label": "Pages (blank = all)",
            "value": "",
            "type": "text"
          }
        ],
        "files": true,
        "input": false,
        "accept": ".pdf",
        "note": "Text extraction requires selectable text; scanned pages need OCR. Markdown export contains extracted paragraphs, not reconstructed tables or heading semantics.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/pdf-to-text/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/pdf-to-text/"
    },
    {
      "id": "pdf-to-word",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Editable DOCX with tested layout/table reconstruction; do not promise perfect conversion.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".pdf",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Processed by the local, self-hosted engine. No third-party conversion service is used. Creates editable paragraphs in reading order. Complex layouts, forms, and tables are not reconstructed. Scans need OCR first.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/pdf-to-word/run",
      "api": {
        "id": "pdf-to-word",
        "name": "PDF to word",
        "category": "pdf-tools",
        "description": "Export selectable PDF text into an editable Word document.",
        "notes": "Processed by the local, self-hosted engine. No third-party conversion service is used. Creates editable paragraphs in reading order. Complex layouts, forms, and tables are not reconstructed. Scans need OCR first.",
        "human_path": "/en/pdf-tools/pdf-to-word/",
        "method": "POST",
        "endpoint": "/api/v1/tools/pdf-to-word/run",
        "schema_url": "/api/v1/tools/pdf-to-word",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/pdf-to-word/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/pdf-to-word/"
    },
    {
      "id": "png-to-pdf",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Image order, page sizing and transparency background; distinguish from JPEG input page.",
      "implementation": {
        "fields": [],
        "files": true,
        "multiple": true,
        "input": false,
        "accept": "image/*,.svg",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/png-to-pdf/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/png-to-pdf/"
    },
    {
      "id": "protect-pdf",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Modern supported encryption and explicit open-password versus permissions controls.",
      "implementation": {
        "fields": [
          {
            "key": "password",
            "label": "New opening password",
            "value": "",
            "type": "password"
          }
        ],
        "files": true,
        "accept": ".pdf",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Processed by the local, self-hosted engine. No third-party conversion service is used. AES-256 encryption. Store your password safely; it cannot be recovered here.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/protect-pdf/run",
      "api": {
        "id": "protect-pdf",
        "name": "Protect PDF",
        "category": "pdf-tools",
        "description": "Encrypt a PDF with a password before sharing it.",
        "notes": "Processed by the local, self-hosted engine. No third-party conversion service is used. AES-256 encryption. Store your password safely; it cannot be recovered here.",
        "human_path": "/en/pdf-tools/protect-pdf/",
        "method": "POST",
        "endpoint": "/api/v1/tools/protect-pdf/run",
        "schema_url": "/api/v1/tools/protect-pdf",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "password": {
                  "type": "string",
                  "description": "New opening password",
                  "default": ""
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/protect-pdf/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/protect-pdf/"
    },
    {
      "id": "redact-pdf",
      "category": "pdf-tools",
      "built": true,
      "requirements": "True removal of underlying text/images, metadata and annotations; black boxes alone do not qualify.",
      "implementation": {
        "fields": [
          {
            "key": "search",
            "label": "Exact text to permanently remove",
            "value": "",
            "type": "text"
          },
          {
            "key": "page",
            "label": "Page (0 means all pages)",
            "value": 0,
            "type": "number",
            "min": 0,
            "max": 500,
            "step": 1
          }
        ],
        "files": true,
        "accept": ".pdf",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Processed by the local, self-hosted engine. No third-party conversion service is used. Permanently removes matching selectable text and overlapping image/vector content, then strips metadata, annotations, and attachments. Scanned text needs OCR first. Inspect the output before sharing.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/redact-pdf/run",
      "api": {
        "id": "redact-pdf",
        "name": "Redact PDF",
        "category": "pdf-tools",
        "description": "Permanently remove matching selectable text from a PDF.",
        "notes": "Processed by the local, self-hosted engine. No third-party conversion service is used. Permanently removes matching selectable text and overlapping image/vector content, then strips metadata, annotations, and attachments. Scanned text needs OCR first. Inspect the output before sharing.",
        "human_path": "/en/pdf-tools/redact-pdf/",
        "method": "POST",
        "endpoint": "/api/v1/tools/redact-pdf/run",
        "schema_url": "/api/v1/tools/redact-pdf",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "search": {
                  "type": "string",
                  "description": "Exact text to permanently remove",
                  "default": ""
                },
                "page": {
                  "type": "number",
                  "description": "Page (0 means all pages)",
                  "default": 0.0,
                  "minimum": 0,
                  "maximum": 500,
                  "multipleOf": 1
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/redact-pdf/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/redact-pdf/"
    },
    {
      "id": "remove-pdf-metadata",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Remove supported document properties and verify output; scope exclusions explicitly.",
      "implementation": {
        "fields": [],
        "files": true,
        "multiple": false,
        "input": false,
        "accept": ".pdf",
        "note": "Page numbers start at 1. Password-encrypted PDFs must be unlocked first.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/remove-pdf-metadata/run",
      "api": {
        "id": "remove-pdf-metadata",
        "name": "Remove PDF metadata",
        "category": "pdf-tools",
        "description": "Clear common document metadata from a PDF copy.",
        "notes": "Page numbers start at 1. Password-encrypted PDFs must be unlocked first.",
        "human_path": "/en/pdf-tools/remove-pdf-metadata/",
        "method": "POST",
        "endpoint": "/api/v1/tools/remove-pdf-metadata/run",
        "schema_url": "/api/v1/tools/remove-pdf-metadata",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/remove-pdf-metadata/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/remove-pdf-metadata/"
    },
    {
      "id": "reorder-pages",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Accessible page thumbnails and keyboard ordering; show final order before save.",
      "implementation": {
        "fields": [
          {
            "key": "pages",
            "label": "Pages (blank = all)",
            "value": "",
            "type": "text"
          }
        ],
        "files": true,
        "multiple": false,
        "input": false,
        "accept": ".pdf",
        "note": "Page numbers start at 1. Password-encrypted PDFs must be unlocked first.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/reorder-pages/run",
      "api": {
        "id": "reorder-pages",
        "name": "Reorder pages",
        "category": "pdf-tools",
        "description": "Arrange PDF pages in a new order.",
        "notes": "Page numbers start at 1. Password-encrypted PDFs must be unlocked first.",
        "human_path": "/en/pdf-tools/reorder-pages/",
        "method": "POST",
        "endpoint": "/api/v1/tools/reorder-pages/run",
        "schema_url": "/api/v1/tools/reorder-pages",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "pages": {
                  "type": "string",
                  "description": "Pages (blank = all)",
                  "default": ""
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/reorder-pages/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/reorder-pages/"
    },
    {
      "id": "repair-pdf",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Recover supported structural errors only; give a clear unrecoverable result.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".pdf",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Processed by the local, self-hosted engine. No third-party conversion service is used. Lossless structural optimisation and supported structural recovery. No image downsampling or guarantee of smaller output.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/repair-pdf/run",
      "api": {
        "id": "repair-pdf",
        "name": "Repair PDF",
        "category": "pdf-tools",
        "description": "Try to recover a readable PDF from a damaged document.",
        "notes": "Processed by the local, self-hosted engine. No third-party conversion service is used. Lossless structural optimisation and supported structural recovery. No image downsampling or guarantee of smaller output.",
        "human_path": "/en/pdf-tools/repair-pdf/",
        "method": "POST",
        "endpoint": "/api/v1/tools/repair-pdf/run",
        "schema_url": "/api/v1/tools/repair-pdf",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/repair-pdf/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/repair-pdf/"
    },
    {
      "id": "resize-pdf-pages",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Paper-size selection, fit/scale and margin handling with page preview.",
      "implementation": {
        "fields": [
          {
            "key": "width",
            "label": "Page width (points)",
            "value": 595,
            "type": "number"
          },
          {
            "key": "height",
            "label": "Page height (points)",
            "value": 842,
            "type": "number"
          }
        ],
        "files": true,
        "multiple": false,
        "input": false,
        "accept": ".pdf",
        "note": "Page numbers start at 1. Password-encrypted PDFs must be unlocked first.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/resize-pdf-pages/run",
      "api": {
        "id": "resize-pdf-pages",
        "name": "Resize PDF pages",
        "category": "pdf-tools",
        "description": "Fit PDF pages onto a new page size.",
        "notes": "Page numbers start at 1. Password-encrypted PDFs must be unlocked first.",
        "human_path": "/en/pdf-tools/resize-pdf-pages/",
        "method": "POST",
        "endpoint": "/api/v1/tools/resize-pdf-pages/run",
        "schema_url": "/api/v1/tools/resize-pdf-pages",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "width": {
                  "type": "number",
                  "description": "Page width (points)",
                  "default": 595.0
                },
                "height": {
                  "type": "number",
                  "description": "Page height (points)",
                  "default": 842.0
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/resize-pdf-pages/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/resize-pdf-pages/"
    },
    {
      "id": "rotate-pdf",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Choose pages and rotation direction; verify visible and saved orientation agree.",
      "implementation": {
        "fields": [
          {
            "key": "pages",
            "label": "Pages (blank = all)",
            "value": "",
            "type": "text"
          },
          {
            "key": "angle",
            "label": "Rotation",
            "value": "90",
            "type": "select",
            "values": [
              "90",
              "180",
              "270"
            ]
          }
        ],
        "files": true,
        "multiple": false,
        "input": false,
        "accept": ".pdf",
        "note": "Page numbers start at 1. Password-encrypted PDFs must be unlocked first.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/rotate-pdf/run",
      "api": {
        "id": "rotate-pdf",
        "name": "Rotate PDF",
        "category": "pdf-tools",
        "description": "Rotate selected PDF pages.",
        "notes": "Page numbers start at 1. Password-encrypted PDFs must be unlocked first.",
        "human_path": "/en/pdf-tools/rotate-pdf/",
        "method": "POST",
        "endpoint": "/api/v1/tools/rotate-pdf/run",
        "schema_url": "/api/v1/tools/rotate-pdf",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "pages": {
                  "type": "string",
                  "description": "Pages (blank = all)",
                  "default": ""
                },
                "angle": {
                  "type": "string",
                  "description": "Rotation",
                  "default": "90",
                  "enum": [
                    "90",
                    "180",
                    "270"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/rotate-pdf/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/rotate-pdf/"
    },
    {
      "id": "scan-to-pdf",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Camera capture, corner correction and page ordering; optional OCR is a separate step.",
      "implementation": {
        "fields": [
          {
            "key": "crop",
            "label": "Automatically detect and crop page edges",
            "value": true,
            "type": "checkbox"
          }
        ],
        "files": true,
        "accept": ".png,.jpg,.jpeg,.webp",
        "multiple": true,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Processed by the local, self-hosted engine. No third-party conversion service is used. Upload photos or scans in page order. Automatic perspective correction works best with a clear page border. Review the exported PDF. Direct camera capture is not included yet.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/scan-to-pdf/run",
      "api": {
        "id": "scan-to-pdf",
        "name": "Scan to PDF",
        "category": "pdf-tools",
        "description": "Combine document photos into a PDF with automatic page detection.",
        "notes": "Processed by the local, self-hosted engine. No third-party conversion service is used. Upload photos or scans in page order. Automatic perspective correction works best with a clear page border. Review the exported PDF. Direct camera capture is not included yet.",
        "human_path": "/en/pdf-tools/scan-to-pdf/",
        "method": "POST",
        "endpoint": "/api/v1/tools/scan-to-pdf/run",
        "schema_url": "/api/v1/tools/scan-to-pdf",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "crop": {
                  "type": "boolean",
                  "description": "Automatically detect and crop page edges",
                  "default": true
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 20,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 20,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/scan-to-pdf/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/scan-to-pdf/"
    },
    {
      "id": "sign-pdf",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Place drawn/uploaded signatures; explicitly distinguish visual signatures from certificate-based signing.",
      "implementation": {
        "fields": [
          {
            "key": "page",
            "label": "Page",
            "value": 1,
            "type": "number"
          },
          {
            "key": "x",
            "label": "X from left (points)",
            "value": 40,
            "type": "number"
          },
          {
            "key": "y",
            "label": "Y from bottom (points)",
            "value": 40,
            "type": "number"
          },
          {
            "key": "width",
            "label": "Signature width (points)",
            "value": 150,
            "type": "number"
          }
        ],
        "files": true,
        "multiple": true,
        "input": false,
        "accept": ".pdf,.png,.jpg,.jpeg",
        "note": "Places an uploaded visual signature. This is not certificate-based digital signing. Select the PDF and signature image together.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/sign-pdf/run",
      "api": {
        "id": "sign-pdf",
        "name": "Sign PDF",
        "category": "pdf-tools",
        "description": "Place a signature image on a PDF page.",
        "notes": "Places an uploaded visual signature. This is not certificate-based digital signing. Select the PDF and signature image together.",
        "human_path": "/en/pdf-tools/sign-pdf/",
        "method": "POST",
        "endpoint": "/api/v1/tools/sign-pdf/run",
        "schema_url": "/api/v1/tools/sign-pdf",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "page": {
                  "type": "number",
                  "description": "Page",
                  "default": 1.0
                },
                "x": {
                  "type": "number",
                  "description": "X from left (points)",
                  "default": 40.0
                },
                "y": {
                  "type": "number",
                  "description": "Y from bottom (points)",
                  "default": 40.0
                },
                "width": {
                  "type": "number",
                  "description": "Signature width (points)",
                  "default": 150.0
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 20,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 20,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/sign-pdf/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/sign-pdf/"
    },
    {
      "id": "split-pdf",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Split by ranges or each page into multiple files; preview output groups before download.",
      "implementation": {
        "fields": [
          {
            "key": "pages",
            "label": "Pages (blank = all)",
            "value": "",
            "type": "text"
          }
        ],
        "files": true,
        "multiple": false,
        "input": false,
        "accept": ".pdf",
        "note": "Page numbers start at 1. Password-encrypted PDFs must be unlocked first.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/split-pdf/run",
      "api": {
        "id": "split-pdf",
        "name": "Split PDF",
        "category": "pdf-tools",
        "description": "Save selected PDF pages as separate files.",
        "notes": "Page numbers start at 1. Password-encrypted PDFs must be unlocked first.",
        "human_path": "/en/pdf-tools/split-pdf/",
        "method": "POST",
        "endpoint": "/api/v1/tools/split-pdf/run",
        "schema_url": "/api/v1/tools/split-pdf",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "pages": {
                  "type": "string",
                  "description": "Pages (blank = all)",
                  "default": ""
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/split-pdf/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/split-pdf/"
    },
    {
      "id": "split-pdf-in-half",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Choose left/right or top/bottom; preserve visible content and selectable text; rotation-aware; crop is not redaction.",
      "implementation": {
        "fields": [
          {
            "key": "direction",
            "label": "Split direction",
            "value": "Left and right",
            "type": "select",
            "values": [
              "Left and right",
              "Top and bottom"
            ]
          }
        ],
        "files": true,
        "input": false,
        "multiple": false,
        "accept": ".pdf",
        "note": "Runs on your device. Up to 100 pages per input. Splits the visible page area; cropped content remains in the PDF. This is not redaction.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/split-pdf-in-half/run",
      "api": {
        "id": "split-pdf-in-half",
        "name": "Split PDF in half",
        "category": "pdf-tools",
        "description": "Split scanned spreads into two pages.",
        "notes": "Runs on your device. Up to 100 pages per input. Splits the visible page area; cropped content remains in the PDF. This is not redaction.",
        "human_path": "/en/pdf-tools/split-pdf-in-half/",
        "method": "POST",
        "endpoint": "/api/v1/tools/split-pdf-in-half/run",
        "schema_url": "/api/v1/tools/split-pdf-in-half",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "direction": {
                  "type": "string",
                  "description": "Split direction",
                  "default": "Left and right",
                  "enum": [
                    "Left and right",
                    "Top and bottom"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/split-pdf-in-half/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/split-pdf-in-half/"
    },
    {
      "id": "svg-to-pdf",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Declare vector-preserving versus raster output; sanitize embedded content and fonts.",
      "implementation": {
        "fields": [],
        "files": true,
        "multiple": true,
        "input": false,
        "accept": "image/*,.svg",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/svg-to-pdf/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/svg-to-pdf/"
    },
    {
      "id": "unlock-pdf",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Remove supported restrictions with authorized access/known password; no recovery guarantee.",
      "implementation": {
        "fields": [
          {
            "key": "password",
            "label": "Current opening password",
            "value": "",
            "type": "password"
          }
        ],
        "files": true,
        "accept": ".pdf",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Processed by the local, self-hosted engine. No third-party conversion service is used. Requires the password for an encrypted document. Does not crack or recover unknown passwords.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/unlock-pdf/run",
      "api": {
        "id": "unlock-pdf",
        "name": "Unlock PDF",
        "category": "pdf-tools",
        "description": "Remove PDF encryption using the correct password.",
        "notes": "Processed by the local, self-hosted engine. No third-party conversion service is used. Requires the password for an encrypted document. Does not crack or recover unknown passwords.",
        "human_path": "/en/pdf-tools/unlock-pdf/",
        "method": "POST",
        "endpoint": "/api/v1/tools/unlock-pdf/run",
        "schema_url": "/api/v1/tools/unlock-pdf",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "password": {
                  "type": "string",
                  "description": "Current opening password",
                  "default": ""
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/unlock-pdf/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/unlock-pdf/"
    },
    {
      "id": "watermark-pdf",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Text/image marks by page range; position and opacity without rasterizing text.",
      "implementation": {
        "fields": [
          {
            "key": "pages",
            "label": "Pages (blank = all)",
            "value": "",
            "type": "text"
          },
          {
            "key": "caption",
            "label": "Watermark",
            "value": "DRAFT",
            "type": "text"
          }
        ],
        "files": true,
        "multiple": false,
        "input": false,
        "accept": ".pdf",
        "note": "Page numbers start at 1. Password-encrypted PDFs must be unlocked first.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/watermark-pdf/run",
      "api": {
        "id": "watermark-pdf",
        "name": "Watermark PDF",
        "category": "pdf-tools",
        "description": "Add a text watermark to selected PDF pages.",
        "notes": "Page numbers start at 1. Password-encrypted PDFs must be unlocked first.",
        "human_path": "/en/pdf-tools/watermark-pdf/",
        "method": "POST",
        "endpoint": "/api/v1/tools/watermark-pdf/run",
        "schema_url": "/api/v1/tools/watermark-pdf",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "pages": {
                  "type": "string",
                  "description": "Pages (blank = all)",
                  "default": ""
                },
                "caption": {
                  "type": "string",
                  "description": "Watermark",
                  "default": "DRAFT"
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/watermark-pdf/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/watermark-pdf/"
    },
    {
      "id": "webp-to-pdf",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Choose static frame for animation explicitly; background and page layout controls.",
      "implementation": {
        "fields": [],
        "files": true,
        "multiple": true,
        "input": false,
        "accept": "image/*,.svg",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/webp-to-pdf/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/webp-to-pdf/"
    },
    {
      "id": "webpage-to-pdf",
      "category": "pdf-tools",
      "built": true,
      "requirements": "Viewport, print layout and isolated public-URL fetching; protect internal network access.",
      "implementation": {
        "fields": [],
        "files": false,
        "accept": "",
        "multiple": false,
        "input": true,
        "processing": "Server required",
        "native": true,
        "extra": true,
        "maxFileBytes": 20971520,
        "note": "Processed locally on this website’s server without an external conversion API. Fetches a public URL and exports static text and links. JavaScript, images, and external stylesheets are not rendered. Private-network URLs are rejected.",
        "experience": {
          "automatic": false,
          "single": true,
          "label": "Website URL",
          "placeholder": "https://happytails.ai",
          "help": "Enter one complete HTTP or HTTPS URL. Only public addresses and ports 80 or 443 are supported.",
          "action": "Save webpage as PDF"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/webpage-to-pdf/run",
      "api": {
        "id": "webpage-to-pdf",
        "name": "Webpage to PDF",
        "category": "pdf-tools",
        "description": "Save a public webpage’s static text and links as a PDF.",
        "notes": "Processed locally on this website’s server without an external conversion API. Fetches a public URL and exports static text and links. JavaScript, images, and external stylesheets are not rendered. Private-network URLs are rejected.",
        "human_path": "/en/pdf-tools/webpage-to-pdf/",
        "method": "POST",
        "endpoint": "/api/v1/tools/webpage-to-pdf/run",
        "schema_url": "/api/v1/tools/webpage-to-pdf",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 0,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/pdf-tools/webpage-to-pdf/",
      "agent_url": "https://happytails.ai/agents/en/pdf-tools/webpage-to-pdf/"
    },
    {
      "id": "inspect-file-metadata",
      "category": "privacy-tools",
      "built": true,
      "requirements": "Initially inspect supported image metadata only; distinguish stored GPS from inferred location.",
      "implementation": {
        "fields": [],
        "files": true,
        "input": false,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/inspect-file-metadata/run",
      "api": {
        "id": "inspect-file-metadata",
        "name": "Inspect file metadata",
        "category": "privacy-tools",
        "description": "Initially inspect supported image metadata only.",
        "notes": "",
        "human_path": "/en/privacy-tools/inspect-file-metadata/",
        "method": "POST",
        "endpoint": "/api/v1/tools/inspect-file-metadata/run",
        "schema_url": "/api/v1/tools/inspect-file-metadata",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/privacy-tools/inspect-file-metadata/",
      "agent_url": "https://happytails.ai/agents/en/privacy-tools/inspect-file-metadata/"
    },
    {
      "id": "passphrase-generator",
      "category": "privacy-tools",
      "built": true,
      "requirements": "Use a documented wordlist and secure independent sampling; explain length/entropy assumptions.",
      "implementation": {
        "fields": [
          {
            "key": "n",
            "label": "Word count",
            "value": 6,
            "type": "number"
          },
          {
            "key": "separator",
            "label": "Separator",
            "value": "-",
            "type": "text"
          }
        ],
        "input": false,
        "note": "Independent secure random selections from the 7,776-word EFF large wordlist. Six words provide about 77.5 bits of selection entropy. Never reuse a passphrase.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/passphrase-generator/run",
      "api": {
        "id": "passphrase-generator",
        "name": "Passphrase generator",
        "category": "privacy-tools",
        "description": "Use a documented wordlist and secure independent sampling.",
        "notes": "Independent secure random selections from the 7,776-word EFF large wordlist. Six words provide about 77.5 bits of selection entropy. Never reuse a passphrase.",
        "human_path": "/en/privacy-tools/passphrase-generator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/passphrase-generator/run",
        "schema_url": "/api/v1/tools/passphrase-generator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "n": {
                  "type": "number",
                  "description": "Word count",
                  "default": 6.0
                },
                "separator": {
                  "type": "string",
                  "description": "Separator",
                  "default": "-"
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/privacy-tools/passphrase-generator/",
      "agent_url": "https://happytails.ai/agents/en/privacy-tools/passphrase-generator/"
    },
    {
      "id": "password-generator",
      "category": "privacy-tools",
      "built": true,
      "requirements": "Cryptographic randomness, length and character controls; no secret logging or network submission.",
      "implementation": {
        "fields": [
          {
            "key": "length",
            "label": "Length",
            "value": 20,
            "type": "number"
          },
          {
            "key": "upper",
            "label": "Uppercase",
            "value": true,
            "type": "checkbox"
          },
          {
            "key": "lower",
            "label": "Lowercase",
            "value": true,
            "type": "checkbox"
          },
          {
            "key": "digits",
            "label": "Numbers",
            "value": true,
            "type": "checkbox"
          },
          {
            "key": "symbols",
            "label": "Symbols",
            "value": true,
            "type": "checkbox"
          }
        ],
        "input": false,
        "note": "Secure browser randomness; each selected group appears. Nothing is saved or uploaded.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/password-generator/run",
      "api": {
        "id": "password-generator",
        "name": "Password generator",
        "category": "privacy-tools",
        "description": "Cryptographic randomness, length and character controls.",
        "notes": "Secure browser randomness; each selected group appears. Nothing is saved or uploaded.",
        "human_path": "/en/privacy-tools/password-generator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/password-generator/run",
        "schema_url": "/api/v1/tools/password-generator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "length": {
                  "type": "number",
                  "description": "Length",
                  "default": 20.0
                },
                "upper": {
                  "type": "boolean",
                  "description": "Uppercase",
                  "default": true
                },
                "lower": {
                  "type": "boolean",
                  "description": "Lowercase",
                  "default": true
                },
                "digits": {
                  "type": "boolean",
                  "description": "Numbers",
                  "default": true
                },
                "symbols": {
                  "type": "boolean",
                  "description": "Symbols",
                  "default": true
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/privacy-tools/password-generator/",
      "agent_url": "https://happytails.ai/agents/en/privacy-tools/password-generator/"
    },
    {
      "id": "redact-image",
      "category": "privacy-tools",
      "built": true,
      "requirements": "Draw opaque redaction areas and export flattened pixels without the source image or its metadata; verify exports contain no recoverable hidden layers; distinguish redaction from cosmetic blur or pixelation.",
      "implementation": {
        "fields": [
          {
            "key": "width",
            "label": "Width (px)",
            "value": "",
            "type": "number",
            "min": 1,
            "max": 16384,
            "step": 1
          },
          {
            "key": "height",
            "label": "Height (px)",
            "value": "",
            "type": "number",
            "min": 1,
            "max": 16384,
            "step": 1
          },
          {
            "key": "x",
            "label": "Left (px)",
            "value": 0,
            "type": "number",
            "min": 0,
            "step": 1
          },
          {
            "key": "y",
            "label": "Top (px)",
            "value": 0,
            "type": "number",
            "min": 0,
            "step": 1
          }
        ],
        "files": true,
        "accept": "image/*,.svg,.avif",
        "input": false,
        "note": "Specify a black rectangle in source pixels. The PNG export is flattened and contains no source layers. Inspect the downloaded image before sharing.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/privacy-tools/redact-image/",
      "agent_url": "https://happytails.ai/agents/en/privacy-tools/redact-image/"
    },
    {
      "id": "redact-personal-information",
      "category": "privacy-tools",
      "built": true,
      "requirements": "Suggest personal-information spans with deterministic pattern checks plus optional model assistance; let users approve each redaction; export plain text; do not claim complete anonymization.",
      "implementation": {
        "fields": [],
        "files": false,
        "accept": "",
        "multiple": false,
        "input": true,
        "processing": "Server required",
        "native": true,
        "ai": false,
        "maxFileBytes": 20971520,
        "note": "Suggest redactions in English text using a local entity model and contact patterns. Review names, emails, phone numbers and street addresses in the JSON preview. Private details may be missed and public text may be flagged. Up to 16,000 characters. This does not guarantee anonymization.",
        "extra": true,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/redact-personal-information/run",
      "api": {
        "id": "redact-personal-information",
        "name": "Redact personal information",
        "category": "privacy-tools",
        "description": "Suggest redactions in English text using a local entity model and contact patterns.",
        "notes": "Suggest redactions in English text using a local entity model and contact patterns. Review names, emails, phone numbers and street addresses in the JSON preview. Private details may be missed and public text may be flagged. Up to 16,000 characters. This does not guarantee anonymization.",
        "human_path": "/en/privacy-tools/redact-personal-information/",
        "method": "POST",
        "endpoint": "/api/v1/tools/redact-personal-information/run",
        "schema_url": "/api/v1/tools/redact-personal-information",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 0,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/privacy-tools/redact-personal-information/",
      "agent_url": "https://happytails.ai/agents/en/privacy-tools/redact-personal-information/"
    },
    {
      "id": "audio-to-text",
      "category": "speech-tools",
      "built": true,
      "requirements": "Upload audio; select or detect language; edit timestamped transcript; export TXT and JSON; show uncertain passages and suppress silence hallucinations. Test accents, noise and long-file chunk boundaries.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".wav,.mp3,.m4a,.flac,.mp4,.mov,.webm",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "ai": true,
        "maxFileBytes": 20971520,
        "note": "Runs with local model weights on this website’s server. No external AI API is used. Review the result for errors. Local Whisper tiny. Clips up to five minutes; review words and timing.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/audio-to-text/run",
      "api": {
        "id": "audio-to-text",
        "name": "Audio to text",
        "category": "speech-tools",
        "description": "Transcribe a short audio recording into text and timed JSON.",
        "notes": "Runs with local model weights on this website’s server. No external AI API is used. Review the result for errors. Local Whisper tiny. Clips up to five minutes; review words and timing.",
        "human_path": "/en/speech-tools/audio-to-text/",
        "method": "POST",
        "endpoint": "/api/v1/tools/audio-to-text/run",
        "schema_url": "/api/v1/tools/audio-to-text",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/speech-tools/audio-to-text/",
      "agent_url": "https://happytails.ai/agents/en/speech-tools/audio-to-text/"
    },
    {
      "id": "audio-translator",
      "category": "speech-tools",
      "built": true,
      "requirements": "Transcribe then translate into a selected language; retain source transcript and timing; show bilingual text and editable terminology. This tool produces text, not dubbed audio.",
      "implementation": {
        "fields": [
          {
            "key": "language",
            "label": "Translate to",
            "type": "select",
            "value": "English",
            "values": [
              "English",
              "Spanish",
              "French",
              "German",
              "Portuguese"
            ]
          }
        ],
        "files": true,
        "accept": ".wav,.mp3,.m4a,.flac,.mp4,.mov,.webm",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "ai": true,
        "maxFileBytes": 20971520,
        "note": "Runs with local model weights on this website’s server. No external AI API is used. Review the result for errors. Local Whisper tiny. Clips up to five minutes; review words and timing.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/audio-translator/run",
      "api": {
        "id": "audio-translator",
        "name": "Audio translator",
        "category": "speech-tools",
        "description": "Transcribe a recording and translate its speech into text.",
        "notes": "Runs with local model weights on this website’s server. No external AI API is used. Review the result for errors. Local Whisper tiny. Clips up to five minutes; review words and timing.",
        "human_path": "/en/speech-tools/audio-translator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/audio-translator/run",
        "schema_url": "/api/v1/tools/audio-translator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "language": {
                  "type": "string",
                  "description": "Translate to",
                  "default": "English",
                  "enum": [
                    "English",
                    "Spanish",
                    "French",
                    "German",
                    "Portuguese"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/speech-tools/audio-translator/",
      "agent_url": "https://happytails.ai/agents/en/speech-tools/audio-translator/"
    },
    {
      "id": "meeting-notes-generator",
      "category": "speech-tools",
      "built": true,
      "requirements": "Create decisions and action items from supplied meeting transcripts; attach source quotes; leave owner and due date blank when unstated; editable export.",
      "implementation": {
        "fields": [],
        "files": false,
        "accept": "",
        "multiple": false,
        "input": true,
        "processing": "Server required",
        "native": true,
        "ai": true,
        "maxFileBytes": 20971520,
        "note": "Runs with local model weights on this website’s server. No external AI API is used. Review the result for errors. At most 16,000 source characters. Generated suggestions require your review.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/meeting-notes-generator/run",
      "api": {
        "id": "meeting-notes-generator",
        "name": "Meeting notes generator",
        "category": "speech-tools",
        "description": "Find decisions, action items and open questions in meeting notes.",
        "notes": "Runs with local model weights on this website’s server. No external AI API is used. Review the result for errors. At most 16,000 source characters. Generated suggestions require your review.",
        "human_path": "/en/speech-tools/meeting-notes-generator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/meeting-notes-generator/run",
        "schema_url": "/api/v1/tools/meeting-notes-generator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 0,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/speech-tools/meeting-notes-generator/",
      "agent_url": "https://happytails.ai/agents/en/speech-tools/meeting-notes-generator/"
    },
    {
      "id": "pdf-to-audio",
      "category": "speech-tools",
      "built": true,
      "requirements": "Extract PDF reading order with preview; choose sections; generate chaptered audio. OCR optional for scans; tables and multi-column layouts need review before synthesis.",
      "implementation": {
        "fields": [
          {
            "key": "rate",
            "label": "Reading speed (words per minute)",
            "value": 170,
            "type": "number",
            "min": 80,
            "max": 300,
            "step": 1
          }
        ],
        "files": true,
        "accept": ".pdf",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "extra": true,
        "maxFileBytes": 20971520,
        "note": "Processed locally on this website’s server without an external conversion API. Uses the installed local macOS voice. Up to 6,000 extracted characters. Scans need OCR first. Linux needs a separate local voice engine.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/pdf-to-audio/run",
      "api": {
        "id": "pdf-to-audio",
        "name": "PDF to audio",
        "category": "speech-tools",
        "description": "Read selectable PDF text aloud using a local system voice.",
        "notes": "Processed locally on this website’s server without an external conversion API. Uses the installed local macOS voice. Up to 6,000 extracted characters. Scans need OCR first. Linux needs a separate local voice engine.",
        "human_path": "/en/speech-tools/pdf-to-audio/",
        "method": "POST",
        "endpoint": "/api/v1/tools/pdf-to-audio/run",
        "schema_url": "/api/v1/tools/pdf-to-audio",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "rate": {
                  "type": "number",
                  "description": "Reading speed (words per minute)",
                  "default": 170.0,
                  "minimum": 80,
                  "maximum": 300,
                  "multipleOf": 1
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/speech-tools/pdf-to-audio/",
      "agent_url": "https://happytails.ai/agents/en/speech-tools/pdf-to-audio/"
    },
    {
      "id": "podcast-chapter-generator",
      "category": "speech-tools",
      "built": true,
      "requirements": "Propose timestamped topic chapters from a transcript; align boundaries to audio; let users rename and merge; no invented timestamps for untimed text.",
      "implementation": {
        "fields": [],
        "files": false,
        "accept": "",
        "multiple": false,
        "input": true,
        "processing": "Server required",
        "native": true,
        "ai": true,
        "maxFileBytes": 20971520,
        "note": "Runs with local model weights on this website’s server. No external AI API is used. Review the result for errors. At most 16,000 source characters. Generated suggestions require your review.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/podcast-chapter-generator/run",
      "api": {
        "id": "podcast-chapter-generator",
        "name": "Podcast chapter generator",
        "category": "speech-tools",
        "description": "Draft podcast chapters using timestamps already in your transcript.",
        "notes": "Runs with local model weights on this website’s server. No external AI API is used. Review the result for errors. At most 16,000 source characters. Generated suggestions require your review.",
        "human_path": "/en/speech-tools/podcast-chapter-generator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/podcast-chapter-generator/run",
        "schema_url": "/api/v1/tools/podcast-chapter-generator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 0,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/speech-tools/podcast-chapter-generator/",
      "agent_url": "https://happytails.ai/agents/en/speech-tools/podcast-chapter-generator/"
    },
    {
      "id": "pronunciation-player",
      "category": "speech-tools",
      "built": true,
      "requirements": "Listen to short words or sentences in a selected language with slow replay; compare available stock voices; no accent-scoring or phonetic-accuracy guarantee.",
      "implementation": {
        "fields": [],
        "input": false,
        "note": "Uses voices supplied by your browser or operating system. Some voices may use the provider’s network service. Playback only; audio-file export is not supported.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": true
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": false,
        "name": null,
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/speech-tools/pronunciation-player/",
      "agent_url": "https://happytails.ai/agents/en/speech-tools/pronunciation-player/"
    },
    {
      "id": "read-aloud",
      "category": "speech-tools",
      "built": true,
      "requirements": "Read pasted text with installed browser voices; play pause stop and speed controls; label remote voices; do not promise MP3 export or offline processing for all voices.",
      "implementation": {
        "fields": [],
        "input": false,
        "note": "Uses voices supplied by your browser or operating system. Some voices may use the provider’s network service. Playback only; audio-file export is not supported.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": true
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": false,
        "name": null,
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/speech-tools/read-aloud/",
      "agent_url": "https://happytails.ai/agents/en/speech-tools/read-aloud/"
    },
    {
      "id": "speaker-diarization",
      "category": "speech-tools",
      "built": true,
      "requirements": "Label speaker turns as Speaker 1 and Speaker 2; let users merge and rename speakers; review overlap; export timestamped JSON. Does not identify people by voice.",
      "implementation": {
        "fields": [
          {
            "key": "speakers",
            "label": "Number of speakers (0 to estimate)",
            "type": "number",
            "value": 0,
            "min": 0,
            "max": 6,
            "step": 1
          }
        ],
        "files": true,
        "accept": ".wav,.mp3,.m4a,.flac,.mp4,.mov,.webm",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "ai": false,
        "maxFileBytes": 20971520,
        "note": "Group non-overlapping voices using local ECAPA speaker embeddings. Up to one minute. Returns speaker labels and approximate 250 ms timestamps. It does not identify people or separate overlapping speech. Review short turns and noisy recordings.",
        "extra": true,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/speaker-diarization/run",
      "api": {
        "id": "speaker-diarization",
        "name": "Speaker diarization",
        "category": "speech-tools",
        "description": "Group non-overlapping voices using local ECAPA speaker embeddings.",
        "notes": "Group non-overlapping voices using local ECAPA speaker embeddings. Up to one minute. Returns speaker labels and approximate 250 ms timestamps. It does not identify people or separate overlapping speech. Review short turns and noisy recordings.",
        "human_path": "/en/speech-tools/speaker-diarization/",
        "method": "POST",
        "endpoint": "/api/v1/tools/speaker-diarization/run",
        "schema_url": "/api/v1/tools/speaker-diarization",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "speakers": {
                  "type": "number",
                  "description": "Number of speakers (0 to estimate)",
                  "default": 0.0,
                  "minimum": 0,
                  "maximum": 6,
                  "multipleOf": 1
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/speech-tools/speaker-diarization/",
      "agent_url": "https://happytails.ai/agents/en/speech-tools/speaker-diarization/"
    },
    {
      "id": "text-to-speech",
      "category": "speech-tools",
      "built": true,
      "requirements": "Generate downloadable WAV from text using stock voices; choose language and speed; preview short passages; handle punctuation and long-text chunking. Text-to-voice and voiceover are aliases or modes.",
      "implementation": {
        "fields": [],
        "input": false,
        "note": "Uses voices supplied by your browser or operating system. Some voices may use the provider’s network service. Playback only; audio-file export is not supported.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": true
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": false,
        "name": null,
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/speech-tools/text-to-speech/",
      "agent_url": "https://happytails.ai/agents/en/speech-tools/text-to-speech/"
    },
    {
      "id": "transcript-editor",
      "category": "speech-tools",
      "built": true,
      "requirements": "Import transcript JSON and local audio; edit text and timestamps side by side; find and replace; preserve original copy; no model is needed for basic editing.",
      "implementation": {
        "fields": [],
        "note": "Edit the transcript directly above, then copy or download your changes.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/transcript-editor/run",
      "api": {
        "id": "transcript-editor",
        "name": "Transcript editor",
        "category": "speech-tools",
        "description": "Import transcript JSON and local audio.",
        "notes": "Edit the transcript directly above, then copy or download your changes.",
        "human_path": "/en/speech-tools/transcript-editor/",
        "method": "POST",
        "endpoint": "/api/v1/tools/transcript-editor/run",
        "schema_url": "/api/v1/tools/transcript-editor",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/speech-tools/transcript-editor/",
      "agent_url": "https://happytails.ai/agents/en/speech-tools/transcript-editor/"
    },
    {
      "id": "transcript-search",
      "category": "speech-tools",
      "built": true,
      "requirements": "Search locally imported timestamped transcripts by phrase and semantic similarity; return matched passages and playback times; no generated claims needed.",
      "implementation": {
        "fields": [
          {
            "key": "query",
            "label": "Find phrase",
            "value": "",
            "type": "text"
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/transcript-search/run",
      "api": {
        "id": "transcript-search",
        "name": "Transcript search",
        "category": "speech-tools",
        "description": "Search locally imported timestamped transcripts by phrase and semantic similarity.",
        "notes": "",
        "human_path": "/en/speech-tools/transcript-search/",
        "method": "POST",
        "endpoint": "/api/v1/tools/transcript-search/run",
        "schema_url": "/api/v1/tools/transcript-search",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "query": {
                  "type": "string",
                  "description": "Find phrase",
                  "default": ""
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/speech-tools/transcript-search/",
      "agent_url": "https://happytails.ai/agents/en/speech-tools/transcript-search/"
    },
    {
      "id": "transcript-summarizer",
      "category": "speech-tools",
      "built": true,
      "requirements": "Summarize an uploaded transcript; link each claim to source timestamps where present; quote evidence; distinguish inference; do not invent missing context.",
      "implementation": {
        "fields": [],
        "files": false,
        "accept": "",
        "multiple": false,
        "input": true,
        "processing": "Server required",
        "native": true,
        "ai": true,
        "maxFileBytes": 20971520,
        "note": "Runs with local model weights on this website’s server. No external AI API is used. Review the result for errors. At most 16,000 source characters. Generated suggestions require your review.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/transcript-summarizer/run",
      "api": {
        "id": "transcript-summarizer",
        "name": "Transcript summarizer",
        "category": "speech-tools",
        "description": "Summarize a transcript with supporting source quotations.",
        "notes": "Runs with local model weights on this website’s server. No external AI API is used. Review the result for errors. At most 16,000 source characters. Generated suggestions require your review.",
        "human_path": "/en/speech-tools/transcript-summarizer/",
        "method": "POST",
        "endpoint": "/api/v1/tools/transcript-summarizer/run",
        "schema_url": "/api/v1/tools/transcript-summarizer",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 0,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/speech-tools/transcript-summarizer/",
      "agent_url": "https://happytails.ai/agents/en/speech-tools/transcript-summarizer/"
    },
    {
      "id": "video-dubbing",
      "category": "speech-tools",
      "built": true,
      "requirements": "Translate user-uploaded video and synthesize replacement stock-voice audio; preview timing and preserve background audio where possible. No automatic identity cloning or lip-sync promise.",
      "implementation": {
        "fields": [
          {
            "key": "language",
            "label": "Translation language",
            "type": "select",
            "value": "Spanish",
            "values": [
              "English",
              "Spanish",
              "French",
              "Portuguese"
            ]
          }
        ],
        "files": true,
        "accept": ".mp4,.mov,.webm,.mkv",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "ai": false,
        "maxFileBytes": 20971520,
        "note": "Translate speech and replace the audio using an installed local system voice. Up to 20 seconds and eight speech segments. Voice cloning, music preservation and lip sync are not included. Review words and timing. All processing uses this server.",
        "extra": true,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/video-dubbing/run",
      "api": {
        "id": "video-dubbing",
        "name": "Video dubbing",
        "category": "speech-tools",
        "description": "Translate speech and replace the audio using an installed local system voice.",
        "notes": "Translate speech and replace the audio using an installed local system voice. Up to 20 seconds and eight speech segments. Voice cloning, music preservation and lip sync are not included. Review words and timing. All processing uses this server.",
        "human_path": "/en/speech-tools/video-dubbing/",
        "method": "POST",
        "endpoint": "/api/v1/tools/video-dubbing/run",
        "schema_url": "/api/v1/tools/video-dubbing",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "language": {
                  "type": "string",
                  "description": "Translation language",
                  "default": "Spanish",
                  "enum": [
                    "English",
                    "Spanish",
                    "French",
                    "Portuguese"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/speech-tools/video-dubbing/",
      "agent_url": "https://happytails.ai/agents/en/speech-tools/video-dubbing/"
    },
    {
      "id": "video-to-text",
      "category": "speech-tools",
      "built": true,
      "requirements": "Extract uploaded video audio locally when supported; transcribe with seekable timestamps; export text. Distinct video preview workflow; do not download arbitrary third-party video URLs.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".wav,.mp3,.m4a,.flac,.mp4,.mov,.webm",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "ai": true,
        "maxFileBytes": 20971520,
        "note": "Runs with local model weights on this website’s server. No external AI API is used. Review the result for errors. Local Whisper tiny. Clips up to five minutes; review words and timing.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/video-to-text/run",
      "api": {
        "id": "video-to-text",
        "name": "Video to text",
        "category": "speech-tools",
        "description": "Transcribe a video’s speech into text and timed JSON.",
        "notes": "Runs with local model weights on this website’s server. No external AI API is used. Review the result for errors. Local Whisper tiny. Clips up to five minutes; review words and timing.",
        "human_path": "/en/speech-tools/video-to-text/",
        "method": "POST",
        "endpoint": "/api/v1/tools/video-to-text/run",
        "schema_url": "/api/v1/tools/video-to-text",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/speech-tools/video-to-text/",
      "agent_url": "https://happytails.ai/agents/en/speech-tools/video-to-text/"
    },
    {
      "id": "voice-cloning",
      "category": "speech-tools",
      "built": true,
      "requirements": "Evaluate consented own-voice synthesis as a separate future workflow with revocable voice profiles and clear disclosure. Do not include celebrity voice presets; rights and model quality require review.",
      "implementation": {
        "fields": [
          {
            "key": "consent",
            "label": "This is my own voice, or I have permission to synthesize it",
            "type": "checkbox",
            "value": false
          }
        ],
        "files": true,
        "accept": ".wav,.mp3,.m4a,.flac,.mp4,.mov,.webm",
        "multiple": false,
        "input": true,
        "processing": "Server required",
        "native": true,
        "ai": false,
        "maxFileBytes": 20971520,
        "note": "Create a short English speech sample from a voice you are permitted to use. Upload 3 to 15 seconds of clear speech and enter up to 160 characters. Local Chatterbox processing, built-in watermark, and no saved voice profile. Disclose synthetic audio. Review similarity and pronunciation; results may vary. Allow up to three minutes for this experimental local voice model.",
        "extra": true,
        "timeoutSeconds": 180,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Generate synthetic speech"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/voice-cloning/run",
      "api": {
        "id": "voice-cloning",
        "name": "Voice cloning",
        "category": "speech-tools",
        "description": "Create a short English speech sample from a voice you are permitted to use.",
        "notes": "Create a short English speech sample from a voice you are permitted to use. Upload 3 to 15 seconds of clear speech and enter up to 160 characters. Local Chatterbox processing, built-in watermark, and no saved voice profile. Disclose synthetic audio. Review similarity and pronunciation; results may vary. Allow up to three minutes for this experimental local voice model.",
        "human_path": "/en/speech-tools/voice-cloning/",
        "method": "POST",
        "endpoint": "/api/v1/tools/voice-cloning/run",
        "schema_url": "/api/v1/tools/voice-cloning",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "consent": {
                  "type": "boolean",
                  "description": "This is my own voice, or I have permission to synthesize it",
                  "default": false
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 180
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/speech-tools/voice-cloning/",
      "agent_url": "https://happytails.ai/agents/en/speech-tools/voice-cloning/"
    },
    {
      "id": "voice-to-text",
      "category": "speech-tools",
      "built": true,
      "requirements": "Record microphone dictation with explicit start and stop; distinguish provisional from final words; edit and copy text; disclose local versus uploaded recognition before recording.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".wav,.mp3,.m4a,.flac,.mp4,.mov,.webm",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "ai": true,
        "maxFileBytes": 20971520,
        "note": "Runs with local model weights on this website’s server. No external AI API is used. Review the result for errors. Local Whisper tiny. Clips up to five minutes; review words and timing. Upload a voice recording; direct microphone capture is not yet included.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/voice-to-text/run",
      "api": {
        "id": "voice-to-text",
        "name": "Voice to text",
        "category": "speech-tools",
        "description": "Turn an uploaded voice recording into a transcript.",
        "notes": "Runs with local model weights on this website’s server. No external AI API is used. Review the result for errors. Local Whisper tiny. Clips up to five minutes; review words and timing. Upload a voice recording; direct microphone capture is not yet included.",
        "human_path": "/en/speech-tools/voice-to-text/",
        "method": "POST",
        "endpoint": "/api/v1/tools/voice-to-text/run",
        "schema_url": "/api/v1/tools/voice-to-text",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/speech-tools/voice-to-text/",
      "agent_url": "https://happytails.ai/agents/en/speech-tools/voice-to-text/"
    },
    {
      "id": "voiceover-timing",
      "category": "speech-tools",
      "built": true,
      "requirements": "Fit stock-voice narration to a target duration; report actual duration; let users shorten text and regenerate; avoid stretching speech into unintelligibility.",
      "implementation": {
        "fields": [
          {
            "key": "pace",
            "label": "Speaking words per minute",
            "value": 150,
            "type": "number"
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/voiceover-timing/run",
      "api": {
        "id": "voiceover-timing",
        "name": "Voiceover timing",
        "category": "speech-tools",
        "description": "Estimate the speaking pace needed for a target duration.",
        "notes": "",
        "human_path": "/en/speech-tools/voiceover-timing/",
        "method": "POST",
        "endpoint": "/api/v1/tools/voiceover-timing/run",
        "schema_url": "/api/v1/tools/voiceover-timing",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "pace": {
                  "type": "number",
                  "description": "Speaking words per minute",
                  "default": 150.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/speech-tools/voiceover-timing/",
      "agent_url": "https://happytails.ai/agents/en/speech-tools/voiceover-timing/"
    },
    {
      "id": "compare-csv",
      "category": "spreadsheet-tools",
      "built": true,
      "requirements": "Keyed row diff versus position diff; added/deleted/changed cells and download.",
      "implementation": {
        "fields": [
          {
            "key": "delimiter",
            "label": "CSV separator",
            "value": ",",
            "type": "select",
            "values": [
              ",",
              ";",
              "\t"
            ]
          },
          {
            "key": "other",
            "label": "Second CSV",
            "value": "",
            "type": "textarea"
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/compare-csv/run",
      "api": {
        "id": "compare-csv",
        "name": "Compare CSV",
        "category": "spreadsheet-tools",
        "description": "Keyed row diff versus position diff.",
        "notes": "",
        "human_path": "/en/spreadsheet-tools/compare-csv/",
        "method": "POST",
        "endpoint": "/api/v1/tools/compare-csv/run",
        "schema_url": "/api/v1/tools/compare-csv",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "delimiter": {
                  "type": "string",
                  "description": "CSV separator",
                  "default": ",",
                  "enum": [
                    ",",
                    ";",
                    "\t"
                  ]
                },
                "other": {
                  "type": "string",
                  "description": "Second CSV",
                  "default": ""
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/spreadsheet-tools/compare-csv/",
      "agent_url": "https://happytails.ai/agents/en/spreadsheet-tools/compare-csv/"
    },
    {
      "id": "csv-join",
      "category": "spreadsheet-tools",
      "built": true,
      "requirements": "Inner/left/full joins on explicit keys; duplicate-key cardinality warning and preview.",
      "implementation": {
        "fields": [
          {
            "key": "delimiter",
            "label": "CSV separator",
            "value": ",",
            "type": "select",
            "values": [
              ",",
              ";",
              "\t"
            ]
          },
          {
            "key": "key",
            "label": "Join column",
            "value": "id",
            "type": "text"
          },
          {
            "key": "type",
            "label": "Join",
            "value": "Inner",
            "type": "select",
            "values": [
              "Inner",
              "Left"
            ]
          },
          {
            "key": "other",
            "label": "Second CSV",
            "value": "",
            "type": "textarea"
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "CSV",
          "placeholder": "name,score\nAda,98\nSam,92",
          "help": "Include a header row. Quote cells that contain commas or new lines. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/csv-join/run",
      "api": {
        "id": "csv-join",
        "name": "CSV join",
        "category": "spreadsheet-tools",
        "description": "Inner/left/full joins on explicit keys.",
        "notes": "",
        "human_path": "/en/spreadsheet-tools/csv-join/",
        "method": "POST",
        "endpoint": "/api/v1/tools/csv-join/run",
        "schema_url": "/api/v1/tools/csv-join",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "delimiter": {
                  "type": "string",
                  "description": "CSV separator",
                  "default": ",",
                  "enum": [
                    ",",
                    ";",
                    "\t"
                  ]
                },
                "key": {
                  "type": "string",
                  "description": "Join column",
                  "default": "id"
                },
                "type": {
                  "type": "string",
                  "description": "Join",
                  "default": "Inner",
                  "enum": [
                    "Inner",
                    "Left"
                  ]
                },
                "other": {
                  "type": "string",
                  "description": "Second CSV",
                  "default": ""
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/spreadsheet-tools/csv-join/",
      "agent_url": "https://happytails.ai/agents/en/spreadsheet-tools/csv-join/"
    },
    {
      "id": "csv-pivot",
      "category": "spreadsheet-tools",
      "built": true,
      "requirements": "Row/column groups, counts/sums, blank handling and export.",
      "implementation": {
        "fields": [
          {
            "key": "delimiter",
            "label": "CSV separator",
            "value": ",",
            "type": "select",
            "values": [
              ",",
              ";",
              "\t"
            ]
          },
          {
            "key": "group",
            "label": "Group by column",
            "value": "category",
            "type": "text"
          },
          {
            "key": "value",
            "label": "Sum column",
            "value": "amount",
            "type": "text"
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "CSV",
          "placeholder": "name,score\nAda,98\nSam,92",
          "help": "Include a header row. Quote cells that contain commas or new lines. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/csv-pivot/run",
      "api": {
        "id": "csv-pivot",
        "name": "CSV pivot",
        "category": "spreadsheet-tools",
        "description": "Row/column groups, counts/sums, blank handling and export.",
        "notes": "",
        "human_path": "/en/spreadsheet-tools/csv-pivot/",
        "method": "POST",
        "endpoint": "/api/v1/tools/csv-pivot/run",
        "schema_url": "/api/v1/tools/csv-pivot",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "delimiter": {
                  "type": "string",
                  "description": "CSV separator",
                  "default": ",",
                  "enum": [
                    ",",
                    ";",
                    "\t"
                  ]
                },
                "group": {
                  "type": "string",
                  "description": "Group by column",
                  "default": "category"
                },
                "value": {
                  "type": "string",
                  "description": "Sum column",
                  "default": "amount"
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/spreadsheet-tools/csv-pivot/",
      "agent_url": "https://happytails.ai/agents/en/spreadsheet-tools/csv-pivot/"
    },
    {
      "id": "excel-to-html",
      "category": "spreadsheet-tools",
      "built": true,
      "requirements": "Sheet and range choice; sanitized markup; disclose formatting limitations.",
      "implementation": {
        "fields": [
          {
            "key": "sheet",
            "label": "Worksheet name (blank = first)",
            "value": "",
            "type": "text"
          }
        ],
        "files": true,
        "input": false,
        "accept": ".xlsx,.xls,.ods",
        "note": "Uses stored cell values; formulas are not recalculated. Check dates, identifiers and cached formula results. CSV/JSON export reads one worksheet.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/excel-to-html/run",
      "api": {
        "id": "excel-to-html",
        "name": "Excel to HTML",
        "category": "spreadsheet-tools",
        "description": "Sheet and range choice.",
        "notes": "Uses stored cell values; formulas are not recalculated. Check dates, identifiers and cached formula results. CSV/JSON export reads one worksheet.",
        "human_path": "/en/spreadsheet-tools/excel-to-html/",
        "method": "POST",
        "endpoint": "/api/v1/tools/excel-to-html/run",
        "schema_url": "/api/v1/tools/excel-to-html",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "sheet": {
                  "type": "string",
                  "description": "Worksheet name (blank = first)",
                  "default": ""
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/spreadsheet-tools/excel-to-html/",
      "agent_url": "https://happytails.ai/agents/en/spreadsheet-tools/excel-to-html/"
    },
    {
      "id": "merge-csv",
      "category": "spreadsheet-tools",
      "built": true,
      "requirements": "Append with header alignment; preserve types; source-file column option.",
      "implementation": {
        "fields": [
          {
            "key": "delimiter",
            "label": "CSV separator",
            "value": ",",
            "type": "select",
            "values": [
              ",",
              ";",
              "\t"
            ]
          }
        ],
        "files": true,
        "multiple": true,
        "input": false,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/merge-csv/run",
      "api": {
        "id": "merge-csv",
        "name": "Merge CSV",
        "category": "spreadsheet-tools",
        "description": "Append with header alignment.",
        "notes": "",
        "human_path": "/en/spreadsheet-tools/merge-csv/",
        "method": "POST",
        "endpoint": "/api/v1/tools/merge-csv/run",
        "schema_url": "/api/v1/tools/merge-csv",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "delimiter": {
                  "type": "string",
                  "description": "CSV separator",
                  "default": ",",
                  "enum": [
                    ",",
                    ";",
                    "\t"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 20,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 20,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/spreadsheet-tools/merge-csv/",
      "agent_url": "https://happytails.ai/agents/en/spreadsheet-tools/merge-csv/"
    },
    {
      "id": "ods-to-xlsx",
      "category": "spreadsheet-tools",
      "built": true,
      "requirements": "Test formulas, dates and styles; report unsupported spreadsheet features.",
      "implementation": {
        "fields": [],
        "files": true,
        "input": false,
        "accept": ".ods",
        "note": "Uses stored cell values; formulas are not recalculated. Check dates, identifiers and cached formula results. CSV/JSON export reads one worksheet.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": "Convert file"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/ods-to-xlsx/run",
      "api": {
        "id": "ods-to-xlsx",
        "name": "Ods to XLSX",
        "category": "spreadsheet-tools",
        "description": "Test formulas, dates and styles.",
        "notes": "Uses stored cell values; formulas are not recalculated. Check dates, identifiers and cached formula results. CSV/JSON export reads one worksheet.",
        "human_path": "/en/spreadsheet-tools/ods-to-xlsx/",
        "method": "POST",
        "endpoint": "/api/v1/tools/ods-to-xlsx/run",
        "schema_url": "/api/v1/tools/ods-to-xlsx",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/spreadsheet-tools/ods-to-xlsx/",
      "agent_url": "https://happytails.ai/agents/en/spreadsheet-tools/ods-to-xlsx/"
    },
    {
      "id": "split-excel",
      "category": "spreadsheet-tools",
      "built": true,
      "requirements": "Split sheets or rows; define handling of cross-sheet formulas.",
      "implementation": {
        "fields": [],
        "files": true,
        "input": false,
        "accept": ".xlsx,.xls,.ods",
        "note": "Uses stored cell values; formulas are not recalculated. Check dates, identifiers and cached formula results. CSV/JSON export reads one worksheet.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/split-excel/run",
      "api": {
        "id": "split-excel",
        "name": "Split excel",
        "category": "spreadsheet-tools",
        "description": "Split sheets or rows.",
        "notes": "Uses stored cell values; formulas are not recalculated. Check dates, identifiers and cached formula results. CSV/JSON export reads one worksheet.",
        "human_path": "/en/spreadsheet-tools/split-excel/",
        "method": "POST",
        "endpoint": "/api/v1/tools/split-excel/run",
        "schema_url": "/api/v1/tools/split-excel",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/spreadsheet-tools/split-excel/",
      "agent_url": "https://happytails.ai/agents/en/spreadsheet-tools/split-excel/"
    },
    {
      "id": "xlsx-viewer",
      "category": "spreadsheet-tools",
      "built": true,
      "requirements": "Local workbook browsing with formula/value distinction and date-system handling.",
      "implementation": {
        "fields": [
          {
            "key": "sheet",
            "label": "Worksheet name (blank = first)",
            "value": "",
            "type": "text"
          }
        ],
        "files": true,
        "input": false,
        "accept": ".xlsx,.xls,.ods",
        "note": "Uses stored cell values; formulas are not recalculated. Check dates, identifiers and cached formula results. CSV/JSON export reads one worksheet.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/xlsx-viewer/run",
      "api": {
        "id": "xlsx-viewer",
        "name": "XLSX viewer",
        "category": "spreadsheet-tools",
        "description": "Open an Excel or OpenDocument worksheet as a readable table.",
        "notes": "Uses stored cell values; formulas are not recalculated. Check dates, identifiers and cached formula results. CSV/JSON export reads one worksheet.",
        "human_path": "/en/spreadsheet-tools/xlsx-viewer/",
        "method": "POST",
        "endpoint": "/api/v1/tools/xlsx-viewer/run",
        "schema_url": "/api/v1/tools/xlsx-viewer",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "sheet": {
                  "type": "string",
                  "description": "Worksheet name (blank = first)",
                  "default": ""
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 1,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/spreadsheet-tools/xlsx-viewer/",
      "agent_url": "https://happytails.ai/agents/en/spreadsheet-tools/xlsx-viewer/"
    },
    {
      "id": "ass-to-srt",
      "category": "subtitle-tools",
      "built": true,
      "requirements": "Warn about loss of ASS styling/effects and preserve dialogue/timing.",
      "implementation": {
        "fields": [],
        "note": "Paste editable subtitle text or use Open text file. Styling and cue layout metadata are normalized; review overlaps after editing.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/ass-to-srt/run",
      "api": {
        "id": "ass-to-srt",
        "name": "Ass to SRT",
        "category": "subtitle-tools",
        "description": "Warn about loss of ASS styling/effects and preserve dialogue/timing.",
        "notes": "Paste editable subtitle text or use Open text file. Styling and cue layout metadata are normalized; review overlaps after editing.",
        "human_path": "/en/subtitle-tools/ass-to-srt/",
        "method": "POST",
        "endpoint": "/api/v1/tools/ass-to-srt/run",
        "schema_url": "/api/v1/tools/ass-to-srt",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/subtitle-tools/ass-to-srt/",
      "agent_url": "https://happytails.ai/agents/en/subtitle-tools/ass-to-srt/"
    },
    {
      "id": "auto-subtitles",
      "category": "subtitle-tools",
      "built": true,
      "requirements": "Generate timed captions from audio or video; edit in playback view; enforce readable line lengths; export SRT and VTT from one canonical generator.",
      "implementation": {
        "fields": [],
        "files": true,
        "accept": ".wav,.mp3,.m4a,.flac,.mp4,.mov,.webm",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "ai": true,
        "maxFileBytes": 20971520,
        "note": "Runs with local model weights on this website’s server. No external AI API is used. Review the result for errors. Local Whisper tiny. Clips up to five minutes; review words and timing.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/auto-subtitles/run",
      "api": {
        "id": "auto-subtitles",
        "name": "Auto subtitles",
        "category": "subtitle-tools",
        "description": "Generate draft SRT captions from recorded speech.",
        "notes": "Runs with local model weights on this website’s server. No external AI API is used. Review the result for errors. Local Whisper tiny. Clips up to five minutes; review words and timing.",
        "human_path": "/en/subtitle-tools/auto-subtitles/",
        "method": "POST",
        "endpoint": "/api/v1/tools/auto-subtitles/run",
        "schema_url": "/api/v1/tools/auto-subtitles",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/subtitle-tools/auto-subtitles/",
      "agent_url": "https://happytails.ai/agents/en/subtitle-tools/auto-subtitles/"
    },
    {
      "id": "clean-subtitles",
      "category": "subtitle-tools",
      "built": true,
      "requirements": "Select removal of hearing-impaired cues, tags or empty cues; preserve spoken text.",
      "implementation": {
        "fields": [],
        "note": "Paste editable subtitle text or use Open text file. Styling and cue layout metadata are normalized; review overlaps after editing.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/clean-subtitles/run",
      "api": {
        "id": "clean-subtitles",
        "name": "Clean subtitles",
        "category": "subtitle-tools",
        "description": "Select removal of hearing-impaired cues, tags or empty cues.",
        "notes": "Paste editable subtitle text or use Open text file. Styling and cue layout metadata are normalized; review overlaps after editing.",
        "human_path": "/en/subtitle-tools/clean-subtitles/",
        "method": "POST",
        "endpoint": "/api/v1/tools/clean-subtitles/run",
        "schema_url": "/api/v1/tools/clean-subtitles",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/subtitle-tools/clean-subtitles/",
      "agent_url": "https://happytails.ai/agents/en/subtitle-tools/clean-subtitles/"
    },
    {
      "id": "extract-subtitles",
      "category": "subtitle-tools",
      "built": true,
      "requirements": "Extract embedded selectable tracks; burned-in captions require different OCR work.",
      "implementation": {
        "fields": [
          {
            "key": "track",
            "label": "Subtitle track (starting at 0)",
            "value": 0,
            "type": "number",
            "min": 0,
            "max": 20,
            "step": 1
          },
          {
            "key": "engine",
            "label": "Processing location",
            "type": "select",
            "value": "browser",
            "values": [
              "browser",
              "server"
            ],
            "labels": {
              "browser": "Browser (files stay here)",
              "server": "Local server (larger files)"
            }
          }
        ],
        "files": true,
        "accept": ".mp4,.mov,.mkv,.webm,.avi",
        "multiple": false,
        "input": false,
        "processing": "Browser or server",
        "native": true,
        "maxFileBytes": 20971520,
        "note": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Extracts a selectable text subtitle track as SRT. Burned-in captions and bitmap subtitle tracks are not supported.",
        "hybrid": true,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/extract-subtitles/run",
      "api": {
        "id": "extract-subtitles",
        "name": "Extract subtitles",
        "category": "subtitle-tools",
        "description": "Extract an embedded text subtitle track as SRT.",
        "notes": "Browser processing keeps files on this device. Choosing Local server sends files to this website’s own processor. Extracts a selectable text subtitle track as SRT. Burned-in captions and bitmap subtitle tracks are not supported.",
        "human_path": "/en/subtitle-tools/extract-subtitles/",
        "method": "POST",
        "endpoint": "/api/v1/tools/extract-subtitles/run",
        "schema_url": "/api/v1/tools/extract-subtitles",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "track": {
                  "type": "number",
                  "description": "Subtitle track (starting at 0)",
                  "default": 0.0,
                  "minimum": 0,
                  "maximum": 20,
                  "multipleOf": 1
                },
                "engine": {
                  "type": "string",
                  "description": "Processing location",
                  "default": "browser",
                  "enum": [
                    "browser",
                    "server"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/subtitle-tools/extract-subtitles/",
      "agent_url": "https://happytails.ai/agents/en/subtitle-tools/extract-subtitles/"
    },
    {
      "id": "karaoke-subtitles",
      "category": "subtitle-tools",
      "built": true,
      "requirements": "Generate word-highlight timings from lyrics or a transcript; preview highlighting and export ASS. Singing and accompaniment must be separately evaluated.",
      "implementation": {
        "fields": [
          {
            "key": "transcript",
            "label": "Matching English transcript or lyrics",
            "type": "textarea",
            "value": ""
          }
        ],
        "files": true,
        "accept": ".wav,.mp3,.m4a,.flac,.mp4,.webm",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "extra": true,
        "maxFileBytes": 20971520,
        "note": "Local Whisper forced alignment. English, up to one minute and 5,000 transcript characters. Review word timing; singing and overlapping voices may align poorly.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/karaoke-subtitles/run",
      "api": {
        "id": "karaoke-subtitles",
        "name": "Karaoke subtitles",
        "category": "subtitle-tools",
        "description": "Create word-timed karaoke subtitles from matching speech and text.",
        "notes": "Local Whisper forced alignment. English, up to one minute and 5,000 transcript characters. Review word timing; singing and overlapping voices may align poorly.",
        "human_path": "/en/subtitle-tools/karaoke-subtitles/",
        "method": "POST",
        "endpoint": "/api/v1/tools/karaoke-subtitles/run",
        "schema_url": "/api/v1/tools/karaoke-subtitles",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "transcript": {
                  "type": "string",
                  "description": "Matching English transcript or lyrics",
                  "default": ""
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/subtitle-tools/karaoke-subtitles/",
      "agent_url": "https://happytails.ai/agents/en/subtitle-tools/karaoke-subtitles/"
    },
    {
      "id": "merge-subtitles",
      "category": "subtitle-tools",
      "built": true,
      "requirements": "Merge timelines with offset and overlap handling; preserve original ordering options.",
      "implementation": {
        "fields": [],
        "files": true,
        "multiple": true,
        "input": false,
        "accept": ".srt,.vtt",
        "note": "Merges on the existing timeline; files are not concatenated end-to-end.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/merge-subtitles/run",
      "api": {
        "id": "merge-subtitles",
        "name": "Merge subtitles",
        "category": "subtitle-tools",
        "description": "Merge timelines with offset and overlap handling.",
        "notes": "Merges on the existing timeline; files are not concatenated end-to-end.",
        "human_path": "/en/subtitle-tools/merge-subtitles/",
        "method": "POST",
        "endpoint": "/api/v1/tools/merge-subtitles/run",
        "schema_url": "/api/v1/tools/merge-subtitles",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            },
            "files": {
              "type": "array",
              "maxItems": 20,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 20,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/subtitle-tools/merge-subtitles/",
      "agent_url": "https://happytails.ai/agents/en/subtitle-tools/merge-subtitles/"
    },
    {
      "id": "shift-subtitles",
      "category": "subtitle-tools",
      "built": true,
      "requirements": "Apply positive/negative offset; report negative timestamps and preserve cue order.",
      "implementation": {
        "fields": [
          {
            "key": "seconds",
            "label": "Shift seconds (negative = earlier)",
            "value": 0,
            "type": "number"
          }
        ],
        "note": "Paste editable subtitle text or use Open text file. Styling and cue layout metadata are normalized; review overlaps after editing.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/shift-subtitles/run",
      "api": {
        "id": "shift-subtitles",
        "name": "Shift subtitles",
        "category": "subtitle-tools",
        "description": "Apply positive/negative offset.",
        "notes": "Paste editable subtitle text or use Open text file. Styling and cue layout metadata are normalized; review overlaps after editing.",
        "human_path": "/en/subtitle-tools/shift-subtitles/",
        "method": "POST",
        "endpoint": "/api/v1/tools/shift-subtitles/run",
        "schema_url": "/api/v1/tools/shift-subtitles",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "seconds": {
                  "type": "number",
                  "description": "Shift seconds (negative = earlier)",
                  "default": 0.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/subtitle-tools/shift-subtitles/",
      "agent_url": "https://happytails.ai/agents/en/subtitle-tools/shift-subtitles/"
    },
    {
      "id": "srt-to-ass",
      "category": "subtitle-tools",
      "built": true,
      "requirements": "Generate valid ASS with basic style defaults and explicit video dimensions.",
      "implementation": {
        "fields": [],
        "note": "Paste editable subtitle text or use Open text file. Styling and cue layout metadata are normalized; review overlaps after editing.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "SRT subtitles",
          "placeholder": "1\n00:00:01,000 --> 00:00:02,000\nHello world",
          "help": "Keep the numbered cues and timestamp lines. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/srt-to-ass/run",
      "api": {
        "id": "srt-to-ass",
        "name": "SRT to ass",
        "category": "subtitle-tools",
        "description": "Generate valid ASS with basic style defaults and explicit video dimensions.",
        "notes": "Paste editable subtitle text or use Open text file. Styling and cue layout metadata are normalized; review overlaps after editing.",
        "human_path": "/en/subtitle-tools/srt-to-ass/",
        "method": "POST",
        "endpoint": "/api/v1/tools/srt-to-ass/run",
        "schema_url": "/api/v1/tools/srt-to-ass",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/subtitle-tools/srt-to-ass/",
      "agent_url": "https://happytails.ai/agents/en/subtitle-tools/srt-to-ass/"
    },
    {
      "id": "srt-to-vtt",
      "category": "subtitle-tools",
      "built": true,
      "requirements": "Convert timestamp punctuation and cue structure; preserve supported text and validate timing.",
      "implementation": {
        "fields": [],
        "note": "Paste editable subtitle text or use Open text file. Styling and cue layout metadata are normalized; review overlaps after editing.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "SRT subtitles",
          "placeholder": "1\n00:00:01,000 --> 00:00:02,000\nHello world",
          "help": "Keep the numbered cues and timestamp lines. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/srt-to-vtt/run",
      "api": {
        "id": "srt-to-vtt",
        "name": "SRT to VTT",
        "category": "subtitle-tools",
        "description": "Convert timestamp punctuation and cue structure.",
        "notes": "Paste editable subtitle text or use Open text file. Styling and cue layout metadata are normalized; review overlaps after editing.",
        "human_path": "/en/subtitle-tools/srt-to-vtt/",
        "method": "POST",
        "endpoint": "/api/v1/tools/srt-to-vtt/run",
        "schema_url": "/api/v1/tools/srt-to-vtt",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/subtitle-tools/srt-to-vtt/",
      "agent_url": "https://happytails.ai/agents/en/subtitle-tools/srt-to-vtt/"
    },
    {
      "id": "subtitle-alignment",
      "category": "subtitle-tools",
      "built": true,
      "requirements": "Align a supplied transcript to audio and produce word or segment timestamps; flag unmatched text; forced alignment does not create speaker labels or fix wrong source words.",
      "implementation": {
        "fields": [
          {
            "key": "transcript",
            "label": "Matching English transcript or lyrics",
            "type": "textarea",
            "value": ""
          }
        ],
        "files": true,
        "accept": ".wav,.mp3,.m4a,.flac,.mp4,.webm",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "extra": true,
        "maxFileBytes": 20971520,
        "note": "Local Whisper forced alignment. English, up to one minute and 5,000 transcript characters. Review word timing; singing and overlapping voices may align poorly.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/subtitle-alignment/run",
      "api": {
        "id": "subtitle-alignment",
        "name": "Subtitle alignment",
        "category": "subtitle-tools",
        "description": "Align a matching English transcript to recorded speech.",
        "notes": "Local Whisper forced alignment. English, up to one minute and 5,000 transcript characters. Review word timing; singing and overlapping voices may align poorly.",
        "human_path": "/en/subtitle-tools/subtitle-alignment/",
        "method": "POST",
        "endpoint": "/api/v1/tools/subtitle-alignment/run",
        "schema_url": "/api/v1/tools/subtitle-alignment",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "transcript": {
                  "type": "string",
                  "description": "Matching English transcript or lyrics",
                  "default": ""
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/subtitle-tools/subtitle-alignment/",
      "agent_url": "https://happytails.ai/agents/en/subtitle-tools/subtitle-alignment/"
    },
    {
      "id": "subtitle-editor",
      "category": "subtitle-tools",
      "built": true,
      "requirements": "Cue text/timing editing, validation and export without automatic transcription.",
      "implementation": {
        "fields": [],
        "note": "Paste editable subtitle text or use Open text file. Styling and cue layout metadata are normalized; review overlaps after editing.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/subtitle-editor/run",
      "api": {
        "id": "subtitle-editor",
        "name": "Subtitle editor",
        "category": "subtitle-tools",
        "description": "Cue text/timing editing, validation and export without automatic transcription.",
        "notes": "Paste editable subtitle text or use Open text file. Styling and cue layout metadata are normalized; review overlaps after editing.",
        "human_path": "/en/subtitle-tools/subtitle-editor/",
        "method": "POST",
        "endpoint": "/api/v1/tools/subtitle-editor/run",
        "schema_url": "/api/v1/tools/subtitle-editor",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/subtitle-tools/subtitle-editor/",
      "agent_url": "https://happytails.ai/agents/en/subtitle-tools/subtitle-editor/"
    },
    {
      "id": "subtitle-translator",
      "category": "subtitle-tools",
      "built": true,
      "requirements": "Translate existing SRT or VTT while preserving cue IDs and timings; review line wrapping, reading speed and terminology; retain original alongside translation.",
      "implementation": {
        "fields": [
          {
            "key": "language",
            "label": "Translate to",
            "type": "select",
            "value": "English",
            "values": [
              "English",
              "Spanish",
              "French",
              "German",
              "Portuguese"
            ]
          }
        ],
        "files": true,
        "accept": ".srt,.vtt",
        "multiple": false,
        "input": false,
        "processing": "Server required",
        "native": true,
        "ai": true,
        "maxFileBytes": 20971520,
        "note": "Runs with local model weights on this website’s server. No external AI API is used. Review the result for errors. Preserves cue timestamps. Up to 50 cues. Review translation and reading speed.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/subtitle-translator/run",
      "api": {
        "id": "subtitle-translator",
        "name": "Subtitle translator",
        "category": "subtitle-tools",
        "description": "Translate subtitle text while preserving cue timing.",
        "notes": "Runs with local model weights on this website’s server. No external AI API is used. Review the result for errors. Preserves cue timestamps. Up to 50 cues. Review translation and reading speed.",
        "human_path": "/en/subtitle-tools/subtitle-translator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/subtitle-translator/run",
        "schema_url": "/api/v1/tools/subtitle-translator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "language": {
                  "type": "string",
                  "description": "Translate to",
                  "default": "English",
                  "enum": [
                    "English",
                    "Spanish",
                    "French",
                    "German",
                    "Portuguese"
                  ]
                }
              }
            },
            "files": {
              "type": "array",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "base64"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filename only, no path."
                  },
                  "mime": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional decoded byte count; must match content if supplied."
                  },
                  "base64": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
                  }
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; self-hosted native engine, no external conversion service",
        "limits": {
          "request_bytes": 31457280,
          "input_characters": 1000000,
          "files_bytes": 20971520,
          "max_files": 1,
          "timeout_seconds": 90
        }
      },
      "agent_processing": "Server; self-hosted native engine, no external conversion service",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/subtitle-tools/subtitle-translator/",
      "agent_url": "https://happytails.ai/agents/en/subtitle-tools/subtitle-translator/"
    },
    {
      "id": "subtitles-to-pdf",
      "category": "subtitle-tools",
      "built": true,
      "requirements": "Readable transcript with optional timestamps and page layout.",
      "implementation": {
        "fields": [],
        "note": "Plain-text PDF export. CSV rows are rendered as text; wide tables may need a spreadsheet layout. Standard PDF font character coverage applies.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/subtitles-to-pdf/run",
      "api": {
        "id": "subtitles-to-pdf",
        "name": "Subtitles to PDF",
        "category": "subtitle-tools",
        "description": "Readable transcript with optional timestamps and page layout.",
        "notes": "Plain-text PDF export. CSV rows are rendered as text; wide tables may need a spreadsheet layout. Standard PDF font character coverage applies.",
        "human_path": "/en/subtitle-tools/subtitles-to-pdf/",
        "method": "POST",
        "endpoint": "/api/v1/tools/subtitles-to-pdf/run",
        "schema_url": "/api/v1/tools/subtitles-to-pdf",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/subtitle-tools/subtitles-to-pdf/",
      "agent_url": "https://happytails.ai/agents/en/subtitle-tools/subtitles-to-pdf/"
    },
    {
      "id": "subtitles-to-text",
      "category": "subtitle-tools",
      "built": true,
      "requirements": "Remove timecodes and optionally repeated captions; preserve paragraphs and spoken text.",
      "implementation": {
        "fields": [],
        "note": "Paste editable subtitle text or use Open text file. Styling and cue layout metadata are normalized; review overlaps after editing.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/subtitles-to-text/run",
      "api": {
        "id": "subtitles-to-text",
        "name": "Subtitles to text",
        "category": "subtitle-tools",
        "description": "Remove timecodes and optionally repeated captions.",
        "notes": "Paste editable subtitle text or use Open text file. Styling and cue layout metadata are normalized; review overlaps after editing.",
        "human_path": "/en/subtitle-tools/subtitles-to-text/",
        "method": "POST",
        "endpoint": "/api/v1/tools/subtitles-to-text/run",
        "schema_url": "/api/v1/tools/subtitles-to-text",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/subtitle-tools/subtitles-to-text/",
      "agent_url": "https://happytails.ai/agents/en/subtitle-tools/subtitles-to-text/"
    },
    {
      "id": "vtt-to-srt",
      "category": "subtitle-tools",
      "built": true,
      "requirements": "Warn when VTT styling/position metadata is lost; validate timestamp output.",
      "implementation": {
        "fields": [],
        "note": "Paste editable subtitle text or use Open text file. Styling and cue layout metadata are normalized; review overlaps after editing.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "WebVTT subtitles",
          "placeholder": "WEBVTT\n\n00:00:01.000 --> 00:00:02.000\nHello world",
          "help": "Include the WEBVTT header and timestamped cues. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/vtt-to-srt/run",
      "api": {
        "id": "vtt-to-srt",
        "name": "VTT to SRT",
        "category": "subtitle-tools",
        "description": "Warn when VTT styling/position metadata is lost.",
        "notes": "Paste editable subtitle text or use Open text file. Styling and cue layout metadata are normalized; review overlaps after editing.",
        "human_path": "/en/subtitle-tools/vtt-to-srt/",
        "method": "POST",
        "endpoint": "/api/v1/tools/vtt-to-srt/run",
        "schema_url": "/api/v1/tools/vtt-to-srt",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/subtitle-tools/vtt-to-srt/",
      "agent_url": "https://happytails.ai/agents/en/subtitle-tools/vtt-to-srt/"
    },
    {
      "id": "add-line-numbers",
      "category": "text-tools",
      "built": true,
      "requirements": "Start value, step, padding and blank-line handling.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/add-line-numbers/run",
      "api": {
        "id": "add-line-numbers",
        "name": "Add line numbers",
        "category": "text-tools",
        "description": "Number each line, starting at 1.",
        "notes": "",
        "human_path": "/en/text-tools/add-line-numbers/",
        "method": "POST",
        "endpoint": "/api/v1/tools/add-line-numbers/run",
        "schema_url": "/api/v1/tools/add-line-numbers",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/add-line-numbers/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/add-line-numbers/"
    },
    {
      "id": "add-prefix-suffix",
      "category": "text-tools",
      "built": true,
      "requirements": "Add/remove prefixes and suffixes in one utility; preview exact line endings.",
      "implementation": {
        "fields": [
          {
            "key": "prefix",
            "label": "Prefix",
            "value": "",
            "type": "text"
          },
          {
            "key": "suffix",
            "label": "Suffix",
            "value": "",
            "type": "text"
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/add-prefix-suffix/run",
      "api": {
        "id": "add-prefix-suffix",
        "name": "Add prefix suffix",
        "category": "text-tools",
        "description": "Add a prefix or suffix to every line.",
        "notes": "",
        "human_path": "/en/text-tools/add-prefix-suffix/",
        "method": "POST",
        "endpoint": "/api/v1/tools/add-prefix-suffix/run",
        "schema_url": "/api/v1/tools/add-prefix-suffix",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "prefix": {
                  "type": "string",
                  "description": "Prefix",
                  "default": ""
                },
                "suffix": {
                  "type": "string",
                  "description": "Suffix",
                  "default": ""
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/add-prefix-suffix/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/add-prefix-suffix/"
    },
    {
      "id": "alternating-case",
      "category": "text-tools",
      "built": true,
      "requirements": "Alternate letter case; choose whether spaces reset the pattern.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/alternating-case/run",
      "api": {
        "id": "alternating-case",
        "name": "Alternating case",
        "category": "text-tools",
        "description": "Alternate lowercase and UPPERCASE letters.",
        "notes": "",
        "human_path": "/en/text-tools/alternating-case/",
        "method": "POST",
        "endpoint": "/api/v1/tools/alternating-case/run",
        "schema_url": "/api/v1/tools/alternating-case",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/alternating-case/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/alternating-case/"
    },
    {
      "id": "bold-text",
      "category": "text-tools",
      "built": true,
      "requirements": "Unicode styled characters with preview; clarify it is not font formatting and support varies.",
      "implementation": {
        "fields": [],
        "note": "Unicode styling changes the characters themselves. Font and screen-reader support varies.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/bold-text/run",
      "api": {
        "id": "bold-text",
        "name": "Bold text",
        "category": "text-tools",
        "description": "Turn letters and digits into bold Unicode characters.",
        "notes": "Unicode styling changes the characters themselves. Font and screen-reader support varies.",
        "human_path": "/en/text-tools/bold-text/",
        "method": "POST",
        "endpoint": "/api/v1/tools/bold-text/run",
        "schema_url": "/api/v1/tools/bold-text",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/bold-text/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/bold-text/"
    },
    {
      "id": "bubble-text",
      "category": "text-tools",
      "built": true,
      "requirements": "Circled character mapping; preserve unsupported scripts and accents.",
      "implementation": {
        "fields": [],
        "note": "Unicode styling changes the characters themselves. Font and screen-reader support varies.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/bubble-text/run",
      "api": {
        "id": "bubble-text",
        "name": "Bubble text",
        "category": "text-tools",
        "description": "Turn Latin letters and digits into circled characters.",
        "notes": "Unicode styling changes the characters themselves. Font and screen-reader support varies.",
        "human_path": "/en/text-tools/bubble-text/",
        "method": "POST",
        "endpoint": "/api/v1/tools/bubble-text/run",
        "schema_url": "/api/v1/tools/bubble-text",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/bubble-text/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/bubble-text/"
    },
    {
      "id": "camel-case",
      "category": "text-tools",
      "built": true,
      "requirements": "Convert separators into camelCase; configurable acronyms, digits and non-ASCII handling.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/camel-case/run",
      "api": {
        "id": "camel-case",
        "name": "Camel case",
        "category": "text-tools",
        "description": "Turn words into a camelCase identifier.",
        "notes": "",
        "human_path": "/en/text-tools/camel-case/",
        "method": "POST",
        "endpoint": "/api/v1/tools/camel-case/run",
        "schema_url": "/api/v1/tools/camel-case",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "transform_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/camel-case/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/camel-case/"
    },
    {
      "id": "case-converter",
      "category": "text-tools",
      "built": true,
      "requirements": "Upper/lower/sentence/title modes; locale-aware casing and explicit title-case conventions.",
      "implementation": {
        "fields": [
          {
            "key": "mode",
            "label": "Case",
            "value": "upper",
            "type": "select",
            "values": [
              "upper",
              "lower",
              "camel",
              "pascal",
              "snake",
              "kebab"
            ]
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/case-converter/run",
      "api": {
        "id": "case-converter",
        "name": "Case converter",
        "category": "text-tools",
        "description": "Switch your text between six capitalization styles.",
        "notes": "",
        "human_path": "/en/text-tools/case-converter/",
        "method": "POST",
        "endpoint": "/api/v1/tools/case-converter/run",
        "schema_url": "/api/v1/tools/case-converter",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "mode": {
                  "type": "string",
                  "description": "Case",
                  "default": "upper",
                  "enum": [
                    "upper",
                    "lower",
                    "camel",
                    "pascal",
                    "snake",
                    "kebab"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "transform_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/case-converter/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/case-converter/"
    },
    {
      "id": "character-counter",
      "category": "text-tools",
      "built": true,
      "requirements": "Graphemes, code points, UTF-16 units and UTF-8 bytes; counts with/without spaces clearly labeled.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/character-counter/run",
      "api": {
        "id": "character-counter",
        "name": "Character counter",
        "category": "text-tools",
        "description": "Count visible characters, words, lines and UTF-8 bytes.",
        "notes": "",
        "human_path": "/en/text-tools/character-counter/",
        "method": "POST",
        "endpoint": "/api/v1/tools/character-counter/run",
        "schema_url": "/api/v1/tools/character-counter",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "transform_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/character-counter/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/character-counter/"
    },
    {
      "id": "comma-separated-list",
      "category": "text-tools",
      "built": true,
      "requirements": "Lines to delimited list and reverse; configurable escaping and quoted commas.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/comma-separated-list/run",
      "api": {
        "id": "comma-separated-list",
        "name": "Comma separated list",
        "category": "text-tools",
        "description": "Turn nonempty lines into a comma-separated list.",
        "notes": "",
        "human_path": "/en/text-tools/comma-separated-list/",
        "method": "POST",
        "endpoint": "/api/v1/tools/comma-separated-list/run",
        "schema_url": "/api/v1/tools/comma-separated-list",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/comma-separated-list/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/comma-separated-list/"
    },
    {
      "id": "compare-text",
      "category": "text-tools",
      "built": true,
      "requirements": "Line/word differences with accessible added/deleted markers; whitespace sensitivity.",
      "implementation": {
        "fields": [
          {
            "key": "other",
            "label": "Compare with",
            "value": "",
            "type": "textarea"
          }
        ],
        "note": "Line-based comparison: + added, − removed.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/compare-text/run",
      "api": {
        "id": "compare-text",
        "name": "Compare text",
        "category": "text-tools",
        "description": "Compare two versions of text, line by line.",
        "notes": "Line-based comparison: + added, − removed.",
        "human_path": "/en/text-tools/compare-text/",
        "method": "POST",
        "endpoint": "/api/v1/tools/compare-text/run",
        "schema_url": "/api/v1/tools/compare-text",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "other": {
                  "type": "string",
                  "description": "Compare with",
                  "default": ""
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/compare-text/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/compare-text/"
    },
    {
      "id": "dot-case",
      "category": "text-tools",
      "built": true,
      "requirements": "Dot-separated identifiers with explicit handling of existing punctuation.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/dot-case/run",
      "api": {
        "id": "dot-case",
        "name": "Dot case",
        "category": "text-tools",
        "description": "Join lowercase words.with.dots.",
        "notes": "",
        "human_path": "/en/text-tools/dot-case/",
        "method": "POST",
        "endpoint": "/api/v1/tools/dot-case/run",
        "schema_url": "/api/v1/tools/dot-case",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/dot-case/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/dot-case/"
    },
    {
      "id": "duplicate-word-finder",
      "category": "text-tools",
      "built": true,
      "requirements": "Highlight repeated tokens with case/accent settings and occurrence counts.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/duplicate-word-finder/run",
      "api": {
        "id": "duplicate-word-finder",
        "name": "Duplicate word finder",
        "category": "text-tools",
        "description": "List repeated words and how often they appear.",
        "notes": "",
        "human_path": "/en/text-tools/duplicate-word-finder/",
        "method": "POST",
        "endpoint": "/api/v1/tools/duplicate-word-finder/run",
        "schema_url": "/api/v1/tools/duplicate-word-finder",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/duplicate-word-finder/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/duplicate-word-finder/"
    },
    {
      "id": "emoji-picker",
      "category": "text-tools",
      "built": true,
      "requirements": "Search a versioned Unicode emoji dataset by name and aliases; copy complete sequences including variation selectors, skin tones and joined emoji; explain platform appearance differences and verify dataset licensing.",
      "implementation": {
        "fields": [],
        "note": "Search English emoji labels and aliases, then copy the sequence you need. Unicode artwork differs across platforms.",
        "experience": {
          "automatic": false,
          "single": true,
          "label": "Find an emoji",
          "placeholder": "smile",
          "help": "Search by an English word or alias. Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/emoji-picker/run",
      "api": {
        "id": "emoji-picker",
        "name": "Emoji picker",
        "category": "text-tools",
        "description": "Find emoji by an English name or keyword.",
        "notes": "Search English emoji labels and aliases, then copy the sequence you need. Unicode artwork differs across platforms.",
        "human_path": "/en/text-tools/emoji-picker/",
        "method": "POST",
        "endpoint": "/api/v1/tools/emoji-picker/run",
        "schema_url": "/api/v1/tools/emoji-picker",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/emoji-picker/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/emoji-picker/"
    },
    {
      "id": "extract-emails",
      "category": "text-tools",
      "built": true,
      "requirements": "Extract addresses from user-provided text only; no mailbox access or outreach.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/extract-emails/run",
      "api": {
        "id": "extract-emails",
        "name": "Extract emails",
        "category": "text-tools",
        "description": "Find unique email-like addresses in pasted text.",
        "notes": "",
        "human_path": "/en/text-tools/extract-emails/",
        "method": "POST",
        "endpoint": "/api/v1/tools/extract-emails/run",
        "schema_url": "/api/v1/tools/extract-emails",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/extract-emails/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/extract-emails/"
    },
    {
      "id": "extract-phone-numbers",
      "category": "text-tools",
      "built": true,
      "requirements": "Country context and formatting versus true number validity; local input only.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/extract-phone-numbers/run",
      "api": {
        "id": "extract-phone-numbers",
        "name": "Extract phone numbers",
        "category": "text-tools",
        "description": "Find possible phone numbers in pasted text.",
        "notes": "",
        "human_path": "/en/text-tools/extract-phone-numbers/",
        "method": "POST",
        "endpoint": "/api/v1/tools/extract-phone-numbers/run",
        "schema_url": "/api/v1/tools/extract-phone-numbers",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/extract-phone-numbers/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/extract-phone-numbers/"
    },
    {
      "id": "extract-urls",
      "category": "text-tools",
      "built": true,
      "requirements": "Unique versus all occurrences, punctuation boundaries and CSV/plain-text export.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/extract-urls/run",
      "api": {
        "id": "extract-urls",
        "name": "Extract urls",
        "category": "text-tools",
        "description": "Find unique HTTP and HTTPS links in pasted text.",
        "notes": "",
        "human_path": "/en/text-tools/extract-urls/",
        "method": "POST",
        "endpoint": "/api/v1/tools/extract-urls/run",
        "schema_url": "/api/v1/tools/extract-urls",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/extract-urls/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/extract-urls/"
    },
    {
      "id": "filter-lines",
      "category": "text-tools",
      "built": true,
      "requirements": "Include/exclude substring or regex matches; preserve original order.",
      "implementation": {
        "fields": [
          {
            "key": "find",
            "label": "Contains",
            "value": "",
            "type": "text"
          },
          {
            "key": "action",
            "label": "Action",
            "value": "Keep matching",
            "type": "select",
            "values": [
              "Keep matching",
              "Remove matching"
            ]
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/filter-lines/run",
      "api": {
        "id": "filter-lines",
        "name": "Filter lines",
        "category": "text-tools",
        "description": "Keep or remove lines containing a phrase.",
        "notes": "",
        "human_path": "/en/text-tools/filter-lines/",
        "method": "POST",
        "endpoint": "/api/v1/tools/filter-lines/run",
        "schema_url": "/api/v1/tools/filter-lines",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "find": {
                  "type": "string",
                  "description": "Contains",
                  "default": ""
                },
                "action": {
                  "type": "string",
                  "description": "Action",
                  "default": "Keep matching",
                  "enum": [
                    "Keep matching",
                    "Remove matching"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/filter-lines/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/filter-lines/"
    },
    {
      "id": "find-and-replace",
      "category": "text-tools",
      "built": true,
      "requirements": "Literal/regex modes, case sensitivity, replacement count and undo/preview.",
      "implementation": {
        "fields": [
          {
            "key": "find",
            "label": "Find",
            "value": "",
            "type": "text"
          },
          {
            "key": "replace",
            "label": "Replace with",
            "value": "",
            "type": "text"
          }
        ],
        "note": "Literal, case-sensitive replacement. For regular expressions use Regex tester.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/find-and-replace/run",
      "api": {
        "id": "find-and-replace",
        "name": "Find and replace",
        "category": "text-tools",
        "description": "Replace every exact match with your chosen text.",
        "notes": "Literal, case-sensitive replacement. For regular expressions use Regex tester.",
        "human_path": "/en/text-tools/find-and-replace/",
        "method": "POST",
        "endpoint": "/api/v1/tools/find-and-replace/run",
        "schema_url": "/api/v1/tools/find-and-replace",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "find": {
                  "type": "string",
                  "description": "Find",
                  "default": ""
                },
                "replace": {
                  "type": "string",
                  "description": "Replace with",
                  "default": ""
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/find-and-replace/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/find-and-replace/"
    },
    {
      "id": "html-to-markdown",
      "category": "text-tools",
      "built": true,
      "requirements": "Convert pasted HTML safely; define table/link/image behavior; no implicit remote fetching.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "HTML source",
          "placeholder": "<p>Hello <strong>world</strong>.</p>",
          "help": "Paste HTML markup, not a website URL. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/html-to-markdown/run",
      "api": {
        "id": "html-to-markdown",
        "name": "HTML to markdown",
        "category": "text-tools",
        "description": "Convert HTML markup into Markdown.",
        "notes": "",
        "human_path": "/en/text-tools/html-to-markdown/",
        "method": "POST",
        "endpoint": "/api/v1/tools/html-to-markdown/run",
        "schema_url": "/api/v1/tools/html-to-markdown",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/html-to-markdown/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/html-to-markdown/"
    },
    {
      "id": "html-to-text",
      "category": "text-tools",
      "built": true,
      "requirements": "Preserve readable paragraph structure and links; no remote fetch in initial tool.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "HTML source",
          "placeholder": "<p>Hello <strong>world</strong>.</p>",
          "help": "Paste HTML markup, not a website URL. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "Browser interface",
      "api": null,
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/html-to-text/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/html-to-text/"
    },
    {
      "id": "indent-text",
      "category": "text-tools",
      "built": true,
      "requirements": "Indent/dedent nonempty lines; tabs or spaces; reversible preview.",
      "implementation": {
        "fields": [
          {
            "key": "n",
            "label": "Indent spaces",
            "value": 2,
            "type": "number"
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/indent-text/run",
      "api": {
        "id": "indent-text",
        "name": "Indent text",
        "category": "text-tools",
        "description": "Add spaces at the start of every line.",
        "notes": "",
        "human_path": "/en/text-tools/indent-text/",
        "method": "POST",
        "endpoint": "/api/v1/tools/indent-text/run",
        "schema_url": "/api/v1/tools/indent-text",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "n": {
                  "type": "number",
                  "description": "Indent spaces",
                  "default": 2.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/indent-text/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/indent-text/"
    },
    {
      "id": "invert-case",
      "category": "text-tools",
      "built": true,
      "requirements": "Invert letter case without altering punctuation; preview mappings that change length.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/invert-case/run",
      "api": {
        "id": "invert-case",
        "name": "Invert case",
        "category": "text-tools",
        "description": "Swap uppercase letters to lowercase and back.",
        "notes": "",
        "human_path": "/en/text-tools/invert-case/",
        "method": "POST",
        "endpoint": "/api/v1/tools/invert-case/run",
        "schema_url": "/api/v1/tools/invert-case",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/invert-case/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/invert-case/"
    },
    {
      "id": "italic-text",
      "category": "text-tools",
      "built": true,
      "requirements": "Unicode italic maps with fallback; preserve unsupported accented letters.",
      "implementation": {
        "fields": [],
        "note": "Unicode styling changes the characters themselves. Font and screen-reader support varies.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/italic-text/run",
      "api": {
        "id": "italic-text",
        "name": "Italic text",
        "category": "text-tools",
        "description": "Turn Latin letters into italic Unicode characters.",
        "notes": "Unicode styling changes the characters themselves. Font and screen-reader support varies.",
        "human_path": "/en/text-tools/italic-text/",
        "method": "POST",
        "endpoint": "/api/v1/tools/italic-text/run",
        "schema_url": "/api/v1/tools/italic-text",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/italic-text/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/italic-text/"
    },
    {
      "id": "join-text",
      "category": "text-tools",
      "built": true,
      "requirements": "Join pasted blocks or files with explicit separator; encoding controls.",
      "implementation": {
        "fields": [
          {
            "key": "separator",
            "label": "Join with",
            "value": ", ",
            "type": "text"
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/join-text/run",
      "api": {
        "id": "join-text",
        "name": "Join text",
        "category": "text-tools",
        "description": "Join lines with a separator of your choice.",
        "notes": "",
        "human_path": "/en/text-tools/join-text/",
        "method": "POST",
        "endpoint": "/api/v1/tools/join-text/run",
        "schema_url": "/api/v1/tools/join-text",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "separator": {
                  "type": "string",
                  "description": "Join with",
                  "default": ", "
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/join-text/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/join-text/"
    },
    {
      "id": "kebab-case",
      "category": "text-tools",
      "built": true,
      "requirements": "Hyphenated identifiers; distinguish preserving accents from URL transliteration.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/kebab-case/run",
      "api": {
        "id": "kebab-case",
        "name": "Kebab case",
        "category": "text-tools",
        "description": "Join lowercase words-with-hyphens.",
        "notes": "",
        "human_path": "/en/text-tools/kebab-case/",
        "method": "POST",
        "endpoint": "/api/v1/tools/kebab-case/run",
        "schema_url": "/api/v1/tools/kebab-case",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "transform_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/kebab-case/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/kebab-case/"
    },
    {
      "id": "line-counter",
      "category": "text-tools",
      "built": true,
      "requirements": "Physical lines versus nonempty lines; define trailing newline behavior.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/line-counter/run",
      "api": {
        "id": "line-counter",
        "name": "Line counter",
        "category": "text-tools",
        "description": "Count all lines and nonempty lines in your text.",
        "notes": "",
        "human_path": "/en/text-tools/line-counter/",
        "method": "POST",
        "endpoint": "/api/v1/tools/line-counter/run",
        "schema_url": "/api/v1/tools/line-counter",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/line-counter/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/line-counter/"
    },
    {
      "id": "list-combinations",
      "category": "text-tools",
      "built": true,
      "requirements": "Generate the Cartesian product of input lists; preview result count before generation, cap output safely, configure separators and duplicate handling; distinguish combinations from concatenating lines.",
      "implementation": {
        "fields": [
          {
            "key": "separator",
            "label": "Join items with",
            "value": " ",
            "type": "text"
          }
        ],
        "note": "One item per line. Separate lists with a blank line. Maximum 10,000 results.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Lists to combine",
          "placeholder": "A\nB\n\n1\n2",
          "help": "Put one item per line and leave a blank line between lists. Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/list-combinations/run",
      "api": {
        "id": "list-combinations",
        "name": "List combinations",
        "category": "text-tools",
        "description": "Generate every combination from groups of items.",
        "notes": "One item per line. Separate lists with a blank line. Maximum 10,000 results.",
        "human_path": "/en/text-tools/list-combinations/",
        "method": "POST",
        "endpoint": "/api/v1/tools/list-combinations/run",
        "schema_url": "/api/v1/tools/list-combinations",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "separator": {
                  "type": "string",
                  "description": "Join items with",
                  "default": " "
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/list-combinations/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/list-combinations/"
    },
    {
      "id": "lorem-ipsum",
      "category": "text-tools",
      "built": true,
      "requirements": "Words, sentences or paragraphs; deterministic sample option and plain/HTML output.",
      "implementation": {
        "fields": [
          {
            "key": "n",
            "label": "Paragraphs",
            "value": 3,
            "type": "number"
          }
        ],
        "input": false,
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/lorem-ipsum/run",
      "api": {
        "id": "lorem-ipsum",
        "name": "Lorem ipsum",
        "category": "text-tools",
        "description": "Generate placeholder paragraphs for layout testing.",
        "notes": "",
        "human_path": "/en/text-tools/lorem-ipsum/",
        "method": "POST",
        "endpoint": "/api/v1/tools/lorem-ipsum/run",
        "schema_url": "/api/v1/tools/lorem-ipsum",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "n": {
                  "type": "number",
                  "description": "Paragraphs",
                  "default": 3.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/lorem-ipsum/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/lorem-ipsum/"
    },
    {
      "id": "lowercase",
      "category": "text-tools",
      "built": true,
      "requirements": "Locale-aware lowercase; preserve paragraphs; clear copy/download actions.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/lowercase/run",
      "api": {
        "id": "lowercase",
        "name": "Lowercase",
        "category": "text-tools",
        "description": "Convert text to lowercase as you type.",
        "notes": "",
        "human_path": "/en/text-tools/lowercase/",
        "method": "POST",
        "endpoint": "/api/v1/tools/lowercase/run",
        "schema_url": "/api/v1/tools/lowercase",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "transform_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/lowercase/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/lowercase/"
    },
    {
      "id": "markdown-to-html",
      "category": "text-tools",
      "built": true,
      "requirements": "Specify dialect; preview sanitized rendered HTML and offer source export.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Markdown",
          "placeholder": "## Hello\n\nThis is **bold** text.",
          "help": "Paste Markdown source, including any headings, lists or links. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/markdown-to-html/run",
      "api": {
        "id": "markdown-to-html",
        "name": "Markdown to HTML",
        "category": "text-tools",
        "description": "Convert Markdown into HTML source.",
        "notes": "",
        "human_path": "/en/text-tools/markdown-to-html/",
        "method": "POST",
        "endpoint": "/api/v1/tools/markdown-to-html/run",
        "schema_url": "/api/v1/tools/markdown-to-html",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/markdown-to-html/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/markdown-to-html/"
    },
    {
      "id": "morse-code-translator",
      "category": "text-tools",
      "built": true,
      "requirements": "Encode/decode supported alphabet with separators and optional local audio playback.",
      "implementation": {
        "fields": [
          {
            "key": "direction",
            "label": "Direction",
            "value": "Encode",
            "type": "select",
            "values": [
              "Encode",
              "Decode"
            ]
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/morse-code-translator/run",
      "api": {
        "id": "morse-code-translator",
        "name": "Morse code translator",
        "category": "text-tools",
        "description": "Translate letters and digits to or from Morse code.",
        "notes": "",
        "human_path": "/en/text-tools/morse-code-translator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/morse-code-translator/run",
        "schema_url": "/api/v1/tools/morse-code-translator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "direction": {
                  "type": "string",
                  "description": "Direction",
                  "default": "Encode",
                  "enum": [
                    "Encode",
                    "Decode"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/morse-code-translator/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/morse-code-translator/"
    },
    {
      "id": "number-to-words",
      "category": "text-tools",
      "built": true,
      "requirements": "Language-specific number grammar, decimal and currency modes; large integer precision.",
      "implementation": {
        "fields": [],
        "note": "English integers within the safe precision range.",
        "experience": {
          "automatic": true,
          "single": true,
          "label": "Number",
          "placeholder": "42",
          "help": "Enter the number you want written in English words. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/number-to-words/run",
      "api": {
        "id": "number-to-words",
        "name": "Number to words",
        "category": "text-tools",
        "description": "Write a whole number in English words.",
        "notes": "English integers within the safe precision range.",
        "human_path": "/en/text-tools/number-to-words/",
        "method": "POST",
        "endpoint": "/api/v1/tools/number-to-words/run",
        "schema_url": "/api/v1/tools/number-to-words",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/number-to-words/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/number-to-words/"
    },
    {
      "id": "online-notepad",
      "category": "text-tools",
      "built": true,
      "requirements": "Edit plain text and open or download UTF-8 TXT files; offer opt-in browser autosave with a clear erase action; explain that local storage is device-specific, may be cleared and is not cloud backup.",
      "implementation": {
        "fields": [],
        "note": "Plain-text notes stay in this tab. Download to keep a copy; closing the tab clears unsaved text.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/online-notepad/run",
      "api": {
        "id": "online-notepad",
        "name": "Online notepad",
        "category": "text-tools",
        "description": "Write plain-text notes and download a copy.",
        "notes": "Plain-text notes stay in this tab. Download to keep a copy; closing the tab clears unsaved text.",
        "human_path": "/en/text-tools/online-notepad/",
        "method": "POST",
        "endpoint": "/api/v1/tools/online-notepad/run",
        "schema_url": "/api/v1/tools/online-notepad",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/online-notepad/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/online-notepad/"
    },
    {
      "id": "paragraph-counter",
      "category": "text-tools",
      "built": true,
      "requirements": "Blank-line-delimited paragraphs versus hard line breaks; preview selected rule.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/paragraph-counter/run",
      "api": {
        "id": "paragraph-counter",
        "name": "Paragraph counter",
        "category": "text-tools",
        "description": "Count paragraphs separated by blank lines.",
        "notes": "",
        "human_path": "/en/text-tools/paragraph-counter/",
        "method": "POST",
        "endpoint": "/api/v1/tools/paragraph-counter/run",
        "schema_url": "/api/v1/tools/paragraph-counter",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/paragraph-counter/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/paragraph-counter/"
    },
    {
      "id": "pascal-case",
      "category": "text-tools",
      "built": true,
      "requirements": "Uppercase first identifier segment; configurable acronyms and tokenization.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/pascal-case/run",
      "api": {
        "id": "pascal-case",
        "name": "Pascal case",
        "category": "text-tools",
        "description": "Turn words into a PascalCase identifier.",
        "notes": "",
        "human_path": "/en/text-tools/pascal-case/",
        "method": "POST",
        "endpoint": "/api/v1/tools/pascal-case/run",
        "schema_url": "/api/v1/tools/pascal-case",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "transform_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/pascal-case/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/pascal-case/"
    },
    {
      "id": "randomize-list",
      "category": "text-tools",
      "built": true,
      "requirements": "Shuffle without duplication; preserve each line as one entry.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/randomize-list/run",
      "api": {
        "id": "randomize-list",
        "name": "Randomize list",
        "category": "text-tools",
        "description": "Shuffle lines into a random order.",
        "notes": "",
        "human_path": "/en/text-tools/randomize-list/",
        "method": "POST",
        "endpoint": "/api/v1/tools/randomize-list/run",
        "schema_url": "/api/v1/tools/randomize-list",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/randomize-list/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/randomize-list/"
    },
    {
      "id": "reading-time",
      "category": "text-tools",
      "built": true,
      "requirements": "Editable words-per-minute and language; present estimated time as an estimate.",
      "implementation": {
        "fields": [
          {
            "key": "wpm",
            "label": "Reading words per minute",
            "value": 200,
            "type": "number",
            "min": 1,
            "max": 1000,
            "step": 1
          }
        ],
        "note": "An estimate based on English word segmentation and your selected pace. Pauses, technical material and delivery style can change the actual time.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/reading-time/run",
      "api": {
        "id": "reading-time",
        "name": "Reading time",
        "category": "text-tools",
        "description": "Estimate reading time at your chosen pace.",
        "notes": "An estimate based on English word segmentation and your selected pace. Pauses, technical material and delivery style can change the actual time.",
        "human_path": "/en/text-tools/reading-time/",
        "method": "POST",
        "endpoint": "/api/v1/tools/reading-time/run",
        "schema_url": "/api/v1/tools/reading-time",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "wpm": {
                  "type": "number",
                  "description": "Reading words per minute",
                  "default": 200.0,
                  "minimum": 1,
                  "maximum": 1000,
                  "multipleOf": 1
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/reading-time/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/reading-time/"
    },
    {
      "id": "remove-diacritics",
      "category": "text-tools",
      "built": true,
      "requirements": "Show transliteration preview; explain meaning can change and some letters need special mappings.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/remove-diacritics/run",
      "api": {
        "id": "remove-diacritics",
        "name": "Remove diacritics",
        "category": "text-tools",
        "description": "Remove combining accents from text.",
        "notes": "",
        "human_path": "/en/text-tools/remove-diacritics/",
        "method": "POST",
        "endpoint": "/api/v1/tools/remove-diacritics/run",
        "schema_url": "/api/v1/tools/remove-diacritics",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/remove-diacritics/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/remove-diacritics/"
    },
    {
      "id": "remove-duplicate-lines",
      "category": "text-tools",
      "built": true,
      "requirements": "Case sensitivity, whitespace normalization and keep-first/last; preserve chosen line order.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/remove-duplicate-lines/run",
      "api": {
        "id": "remove-duplicate-lines",
        "name": "Remove duplicate lines",
        "category": "text-tools",
        "description": "Remove repeated lines while keeping their first occurrence.",
        "notes": "",
        "human_path": "/en/text-tools/remove-duplicate-lines/",
        "method": "POST",
        "endpoint": "/api/v1/tools/remove-duplicate-lines/run",
        "schema_url": "/api/v1/tools/remove-duplicate-lines",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "transform_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/remove-duplicate-lines/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/remove-duplicate-lines/"
    },
    {
      "id": "remove-empty-lines",
      "category": "text-tools",
      "built": true,
      "requirements": "Remove blank or whitespace-only lines and show count.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/remove-empty-lines/run",
      "api": {
        "id": "remove-empty-lines",
        "name": "Remove empty lines",
        "category": "text-tools",
        "description": "Remove blank and whitespace-only lines.",
        "notes": "",
        "human_path": "/en/text-tools/remove-empty-lines/",
        "method": "POST",
        "endpoint": "/api/v1/tools/remove-empty-lines/run",
        "schema_url": "/api/v1/tools/remove-empty-lines",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/remove-empty-lines/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/remove-empty-lines/"
    },
    {
      "id": "remove-extra-spaces",
      "category": "text-tools",
      "built": true,
      "requirements": "Separate spaces from line breaks and tabs; preview changes and preserve Unicode text.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/remove-extra-spaces/run",
      "api": {
        "id": "remove-extra-spaces",
        "name": "Remove extra spaces",
        "category": "text-tools",
        "description": "Tidy repeated spaces without losing line breaks.",
        "notes": "",
        "human_path": "/en/text-tools/remove-extra-spaces/",
        "method": "POST",
        "endpoint": "/api/v1/tools/remove-extra-spaces/run",
        "schema_url": "/api/v1/tools/remove-extra-spaces",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "transform_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/remove-extra-spaces/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/remove-extra-spaces/"
    },
    {
      "id": "remove-formatting",
      "category": "text-tools",
      "built": true,
      "requirements": "Paste as plain text; preserve deliberate line breaks; distinguish rich formatting from Unicode styling.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/remove-formatting/run",
      "api": {
        "id": "remove-formatting",
        "name": "Remove formatting",
        "category": "text-tools",
        "description": "Copy pasted content as plain text.",
        "notes": "",
        "human_path": "/en/text-tools/remove-formatting/",
        "method": "POST",
        "endpoint": "/api/v1/tools/remove-formatting/run",
        "schema_url": "/api/v1/tools/remove-formatting",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/remove-formatting/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/remove-formatting/"
    },
    {
      "id": "remove-line-breaks",
      "category": "text-tools",
      "built": true,
      "requirements": "Join wrapped lines while optionally preserving paragraph boundaries.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/remove-line-breaks/run",
      "api": {
        "id": "remove-line-breaks",
        "name": "Remove line breaks",
        "category": "text-tools",
        "description": "Replace each line break with a space.",
        "notes": "",
        "human_path": "/en/text-tools/remove-line-breaks/",
        "method": "POST",
        "endpoint": "/api/v1/tools/remove-line-breaks/run",
        "schema_url": "/api/v1/tools/remove-line-breaks",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/remove-line-breaks/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/remove-line-breaks/"
    },
    {
      "id": "remove-line-numbers",
      "category": "text-tools",
      "built": true,
      "requirements": "Preview matched prefixes; never strip all leading numbers silently.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/remove-line-numbers/run",
      "api": {
        "id": "remove-line-numbers",
        "name": "Remove line numbers",
        "category": "text-tools",
        "description": "Remove common numeric prefixes from lines.",
        "notes": "",
        "human_path": "/en/text-tools/remove-line-numbers/",
        "method": "POST",
        "endpoint": "/api/v1/tools/remove-line-numbers/run",
        "schema_url": "/api/v1/tools/remove-line-numbers",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/remove-line-numbers/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/remove-line-numbers/"
    },
    {
      "id": "remove-punctuation",
      "category": "text-tools",
      "built": true,
      "requirements": "Selectable punctuation groups; preserve decimal points and apostrophes optionally.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/remove-punctuation/run",
      "api": {
        "id": "remove-punctuation",
        "name": "Remove punctuation",
        "category": "text-tools",
        "description": "Remove Unicode punctuation from your text.",
        "notes": "",
        "human_path": "/en/text-tools/remove-punctuation/",
        "method": "POST",
        "endpoint": "/api/v1/tools/remove-punctuation/run",
        "schema_url": "/api/v1/tools/remove-punctuation",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/remove-punctuation/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/remove-punctuation/"
    },
    {
      "id": "repeat-text",
      "category": "text-tools",
      "built": true,
      "requirements": "Repeat count and separator with output-size guardrails.",
      "implementation": {
        "fields": [
          {
            "key": "n",
            "label": "Repeat count",
            "value": 3,
            "type": "number",
            "min": 1,
            "max": 10000,
            "step": 1
          },
          {
            "key": "separator",
            "label": "Between repetitions",
            "value": " ",
            "type": "text"
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/repeat-text/run",
      "api": {
        "id": "repeat-text",
        "name": "Repeat text",
        "category": "text-tools",
        "description": "Repeat text with a separator between copies.",
        "notes": "",
        "human_path": "/en/text-tools/repeat-text/",
        "method": "POST",
        "endpoint": "/api/v1/tools/repeat-text/run",
        "schema_url": "/api/v1/tools/repeat-text",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "n": {
                  "type": "number",
                  "description": "Repeat count",
                  "default": 3.0,
                  "minimum": 1,
                  "maximum": 10000,
                  "multipleOf": 1
                },
                "separator": {
                  "type": "string",
                  "description": "Between repetitions",
                  "default": " "
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/repeat-text/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/repeat-text/"
    },
    {
      "id": "reverse-text",
      "category": "text-tools",
      "built": true,
      "requirements": "Choose graphemes, words or lines; preserve emoji clusters.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/reverse-text/run",
      "api": {
        "id": "reverse-text",
        "name": "Reverse text",
        "category": "text-tools",
        "description": "Reverse the order of visible characters.",
        "notes": "",
        "human_path": "/en/text-tools/reverse-text/",
        "method": "POST",
        "endpoint": "/api/v1/tools/reverse-text/run",
        "schema_url": "/api/v1/tools/reverse-text",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/reverse-text/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/reverse-text/"
    },
    {
      "id": "sentence-case",
      "category": "text-tools",
      "built": true,
      "requirements": "Sentence boundary preview; preserve selected acronyms; distinguish automatic conversion from grammar correction.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/sentence-case/run",
      "api": {
        "id": "sentence-case",
        "name": "Sentence case",
        "category": "text-tools",
        "description": "Capitalize the start of each sentence.",
        "notes": "",
        "human_path": "/en/text-tools/sentence-case/",
        "method": "POST",
        "endpoint": "/api/v1/tools/sentence-case/run",
        "schema_url": "/api/v1/tools/sentence-case",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/sentence-case/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/sentence-case/"
    },
    {
      "id": "sentence-counter",
      "category": "text-tools",
      "built": true,
      "requirements": "Language-aware sentence segmentation; test abbreviations and decimals.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/sentence-counter/run",
      "api": {
        "id": "sentence-counter",
        "name": "Sentence counter",
        "category": "text-tools",
        "description": "Count sentences using English text segmentation.",
        "notes": "",
        "human_path": "/en/text-tools/sentence-counter/",
        "method": "POST",
        "endpoint": "/api/v1/tools/sentence-counter/run",
        "schema_url": "/api/v1/tools/sentence-counter",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/sentence-counter/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/sentence-counter/"
    },
    {
      "id": "slug-generator",
      "category": "text-tools",
      "built": true,
      "requirements": "Unicode versus ASCII transliteration; separators, case and locale-aware output.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/slug-generator/run",
      "api": {
        "id": "slug-generator",
        "name": "Slug generator",
        "category": "text-tools",
        "description": "Create a lowercase, hyphen-separated slug.",
        "notes": "",
        "human_path": "/en/text-tools/slug-generator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/slug-generator/run",
        "schema_url": "/api/v1/tools/slug-generator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/slug-generator/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/slug-generator/"
    },
    {
      "id": "small-text",
      "category": "text-tools",
      "built": true,
      "requirements": "Small caps and superscript modes; disclose incomplete alphabet coverage.",
      "implementation": {
        "fields": [],
        "note": "Unsupported letters are retained; Unicode has no complete superscript or subscript alphabet.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/small-text/run",
      "api": {
        "id": "small-text",
        "name": "Small text",
        "category": "text-tools",
        "description": "Convert supported letters into small-cap Unicode characters.",
        "notes": "Unsupported letters are retained; Unicode has no complete superscript or subscript alphabet.",
        "human_path": "/en/text-tools/small-text/",
        "method": "POST",
        "endpoint": "/api/v1/tools/small-text/run",
        "schema_url": "/api/v1/tools/small-text",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/small-text/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/small-text/"
    },
    {
      "id": "snake-case",
      "category": "text-tools",
      "built": true,
      "requirements": "Underscore identifiers; recognize mixed-case boundaries and acronym groups.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/snake-case/run",
      "api": {
        "id": "snake-case",
        "name": "Snake case",
        "category": "text-tools",
        "description": "Join lowercase words_with_underscores.",
        "notes": "",
        "human_path": "/en/text-tools/snake-case/",
        "method": "POST",
        "endpoint": "/api/v1/tools/snake-case/run",
        "schema_url": "/api/v1/tools/snake-case",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "transform_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/snake-case/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/snake-case/"
    },
    {
      "id": "sort-lines",
      "category": "text-tools",
      "built": true,
      "requirements": "Natural/numeric versus lexical sorting; locale collation and empty-line controls.",
      "implementation": {
        "fields": [
          {
            "key": "order",
            "label": "Sort",
            "value": "Alphabetical",
            "type": "select",
            "values": [
              "Alphabetical",
              "Numeric"
            ]
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/sort-lines/run",
      "api": {
        "id": "sort-lines",
        "name": "Sort lines",
        "category": "text-tools",
        "description": "Sort lines alphabetically or in natural number order.",
        "notes": "",
        "human_path": "/en/text-tools/sort-lines/",
        "method": "POST",
        "endpoint": "/api/v1/tools/sort-lines/run",
        "schema_url": "/api/v1/tools/sort-lines",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "order": {
                  "type": "string",
                  "description": "Sort",
                  "default": "Alphabetical",
                  "enum": [
                    "Alphabetical",
                    "Numeric"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/sort-lines/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/sort-lines/"
    },
    {
      "id": "speaking-time",
      "category": "text-tools",
      "built": true,
      "requirements": "Editable speaking speed, pauses and time target; do not imply exact delivery duration.",
      "implementation": {
        "fields": [
          {
            "key": "wpm",
            "label": "Speaking words per minute",
            "value": 150,
            "type": "number",
            "min": 1,
            "max": 1000,
            "step": 1
          }
        ],
        "note": "An estimate based on English word segmentation and your selected pace. Pauses, technical material and delivery style can change the actual time.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/speaking-time/run",
      "api": {
        "id": "speaking-time",
        "name": "Speaking time",
        "category": "text-tools",
        "description": "Estimate speaking time at your chosen pace.",
        "notes": "An estimate based on English word segmentation and your selected pace. Pauses, technical material and delivery style can change the actual time.",
        "human_path": "/en/text-tools/speaking-time/",
        "method": "POST",
        "endpoint": "/api/v1/tools/speaking-time/run",
        "schema_url": "/api/v1/tools/speaking-time",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "wpm": {
                  "type": "number",
                  "description": "Speaking words per minute",
                  "default": 150.0,
                  "minimum": 1,
                  "maximum": 1000,
                  "multipleOf": 1
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/speaking-time/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/speaking-time/"
    },
    {
      "id": "split-text",
      "category": "text-tools",
      "built": true,
      "requirements": "Delimiter, character length or line-count modes; show resulting blocks.",
      "implementation": {
        "fields": [
          {
            "key": "separator",
            "label": "Split at",
            "value": ",",
            "type": "text"
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/split-text/run",
      "api": {
        "id": "split-text",
        "name": "Split text",
        "category": "text-tools",
        "description": "Split text at an exact separator, placing each part on a new line.",
        "notes": "",
        "human_path": "/en/text-tools/split-text/",
        "method": "POST",
        "endpoint": "/api/v1/tools/split-text/run",
        "schema_url": "/api/v1/tools/split-text",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "separator": {
                  "type": "string",
                  "description": "Split at",
                  "default": ","
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/split-text/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/split-text/"
    },
    {
      "id": "strikethrough-text",
      "category": "text-tools",
      "built": true,
      "requirements": "Combining strike marks; preserve grapheme boundaries; explain rendering variation.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/strikethrough-text/run",
      "api": {
        "id": "strikethrough-text",
        "name": "Strikethrough text",
        "category": "text-tools",
        "description": "Add a strikethrough mark to visible characters.",
        "notes": "",
        "human_path": "/en/text-tools/strikethrough-text/",
        "method": "POST",
        "endpoint": "/api/v1/tools/strikethrough-text/run",
        "schema_url": "/api/v1/tools/strikethrough-text",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/strikethrough-text/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/strikethrough-text/"
    },
    {
      "id": "subscript",
      "category": "text-tools",
      "built": true,
      "requirements": "Unicode digit/letter subset; disclose unsupported characters; optional semantic HTML.",
      "implementation": {
        "fields": [],
        "note": "Unsupported letters are retained; Unicode has no complete superscript or subscript alphabet.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/subscript/run",
      "api": {
        "id": "subscript",
        "name": "Subscript",
        "category": "text-tools",
        "description": "Convert supported letters into subscript Unicode.",
        "notes": "Unsupported letters are retained; Unicode has no complete superscript or subscript alphabet.",
        "human_path": "/en/text-tools/subscript/",
        "method": "POST",
        "endpoint": "/api/v1/tools/subscript/run",
        "schema_url": "/api/v1/tools/subscript",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/subscript/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/subscript/"
    },
    {
      "id": "superscript",
      "category": "text-tools",
      "built": true,
      "requirements": "Unicode character coverage plus semantic HTML option; copy output clearly separated.",
      "implementation": {
        "fields": [],
        "note": "Unsupported letters are retained; Unicode has no complete superscript or subscript alphabet.",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/superscript/run",
      "api": {
        "id": "superscript",
        "name": "Superscript",
        "category": "text-tools",
        "description": "Convert supported letters into superscript Unicode.",
        "notes": "Unsupported letters are retained; Unicode has no complete superscript or subscript alphabet.",
        "human_path": "/en/text-tools/superscript/",
        "method": "POST",
        "endpoint": "/api/v1/tools/superscript/run",
        "schema_url": "/api/v1/tools/superscript",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/superscript/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/superscript/"
    },
    {
      "id": "tabs-to-spaces",
      "category": "text-tools",
      "built": true,
      "requirements": "Tab stops versus literal replacement; configurable width and reverse mode.",
      "implementation": {
        "fields": [
          {
            "key": "n",
            "label": "Spaces per tab",
            "value": 4,
            "type": "number"
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/tabs-to-spaces/run",
      "api": {
        "id": "tabs-to-spaces",
        "name": "Tabs to spaces",
        "category": "text-tools",
        "description": "Replace each tab with a fixed number of spaces.",
        "notes": "",
        "human_path": "/en/text-tools/tabs-to-spaces/",
        "method": "POST",
        "endpoint": "/api/v1/tools/tabs-to-spaces/run",
        "schema_url": "/api/v1/tools/tabs-to-spaces",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "n": {
                  "type": "number",
                  "description": "Spaces per tab",
                  "default": 4.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/tabs-to-spaces/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/tabs-to-spaces/"
    },
    {
      "id": "text-to-image",
      "category": "text-tools",
      "built": true,
      "requirements": "Render user text into an image with fonts and layout; distinguish from AI image generation.",
      "implementation": {
        "fields": [
          {
            "key": "size",
            "label": "Font size",
            "value": 48,
            "type": "number"
          },
          {
            "key": "width",
            "label": "Canvas width",
            "value": 800,
            "type": "number"
          },
          {
            "key": "height",
            "label": "Canvas height",
            "value": 300,
            "type": "number"
          },
          {
            "key": "color",
            "label": "Text",
            "value": "#171717",
            "type": "color"
          },
          {
            "key": "background",
            "label": "Background",
            "value": "#ffffff",
            "type": "color"
          }
        ],
        "note": "SVG export uses your system sans-serif font. Check wrapping and font appearance in the destination.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/text-to-image/run",
      "api": {
        "id": "text-to-image",
        "name": "Text to image",
        "category": "text-tools",
        "description": "Create an SVG image from your text.",
        "notes": "SVG export uses your system sans-serif font. Check wrapping and font appearance in the destination.",
        "human_path": "/en/text-tools/text-to-image/",
        "method": "POST",
        "endpoint": "/api/v1/tools/text-to-image/run",
        "schema_url": "/api/v1/tools/text-to-image",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "size": {
                  "type": "number",
                  "description": "Font size",
                  "default": 48.0
                },
                "width": {
                  "type": "number",
                  "description": "Canvas width",
                  "default": 800.0
                },
                "height": {
                  "type": "number",
                  "description": "Canvas height",
                  "default": 300.0
                },
                "color": {
                  "type": "string",
                  "description": "Text",
                  "default": "#171717"
                },
                "background": {
                  "type": "string",
                  "description": "Background",
                  "default": "#ffffff"
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/text-to-image/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/text-to-image/"
    },
    {
      "id": "title-case",
      "category": "text-tools",
      "built": true,
      "requirements": "Choose language and style rules; preserve acronyms; show exceptions instead of asserting a universal title style.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/title-case/run",
      "api": {
        "id": "title-case",
        "name": "Title case",
        "category": "text-tools",
        "description": "Capitalize the first letter of every word.",
        "notes": "",
        "human_path": "/en/text-tools/title-case/",
        "method": "POST",
        "endpoint": "/api/v1/tools/title-case/run",
        "schema_url": "/api/v1/tools/title-case",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/title-case/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/title-case/"
    },
    {
      "id": "trim-text",
      "category": "text-tools",
      "built": true,
      "requirements": "Leading/trailing whitespace only; offer per-line and whole-document modes.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/trim-text/run",
      "api": {
        "id": "trim-text",
        "name": "Trim text",
        "category": "text-tools",
        "description": "Remove spaces from the start and end of each line.",
        "notes": "",
        "human_path": "/en/text-tools/trim-text/",
        "method": "POST",
        "endpoint": "/api/v1/tools/trim-text/run",
        "schema_url": "/api/v1/tools/trim-text",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/trim-text/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/trim-text/"
    },
    {
      "id": "underline-text",
      "category": "text-tools",
      "built": true,
      "requirements": "Combining underline versus HTML output option; handle whitespace explicitly.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/underline-text/run",
      "api": {
        "id": "underline-text",
        "name": "Underline text",
        "category": "text-tools",
        "description": "Add combining underlines to non-whitespace characters.",
        "notes": "",
        "human_path": "/en/text-tools/underline-text/",
        "method": "POST",
        "endpoint": "/api/v1/tools/underline-text/run",
        "schema_url": "/api/v1/tools/underline-text",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/underline-text/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/underline-text/"
    },
    {
      "id": "uppercase",
      "category": "text-tools",
      "built": true,
      "requirements": "Locale-aware uppercasing; preserve layout and numbers; test accented letters and expanding mappings.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/uppercase/run",
      "api": {
        "id": "uppercase",
        "name": "Uppercase",
        "category": "text-tools",
        "description": "Convert text to UPPERCASE as you type.",
        "notes": "",
        "human_path": "/en/text-tools/uppercase/",
        "method": "POST",
        "endpoint": "/api/v1/tools/uppercase/run",
        "schema_url": "/api/v1/tools/uppercase",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "transform_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/uppercase/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/uppercase/"
    },
    {
      "id": "upside-down-text",
      "category": "text-tools",
      "built": true,
      "requirements": "Reverse graphemes and map supported characters; unsupported symbols remain visible; preview copy output.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/upside-down-text/run",
      "api": {
        "id": "upside-down-text",
        "name": "Upside down text",
        "category": "text-tools",
        "description": "Flip text into an upside-down Unicode style.",
        "notes": "",
        "human_path": "/en/text-tools/upside-down-text/",
        "method": "POST",
        "endpoint": "/api/v1/tools/upside-down-text/run",
        "schema_url": "/api/v1/tools/upside-down-text",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "transform_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/upside-down-text/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/upside-down-text/"
    },
    {
      "id": "wide-text",
      "category": "text-tools",
      "built": true,
      "requirements": "Fullwidth conversion and reverse; preserve characters without fullwidth mappings.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/wide-text/run",
      "api": {
        "id": "wide-text",
        "name": "Wide text",
        "category": "text-tools",
        "description": "Convert basic Latin characters to fullwidth Unicode.",
        "notes": "",
        "human_path": "/en/text-tools/wide-text/",
        "method": "POST",
        "endpoint": "/api/v1/tools/wide-text/run",
        "schema_url": "/api/v1/tools/wide-text",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/wide-text/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/wide-text/"
    },
    {
      "id": "word-counter",
      "category": "text-tools",
      "built": true,
      "requirements": "Define Unicode word/character rules; count with/without spaces and test all launch languages.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/word-counter/run",
      "api": {
        "id": "word-counter",
        "name": "Word counter",
        "category": "text-tools",
        "description": "Count words, characters and lines as you type.",
        "notes": "",
        "human_path": "/en/text-tools/word-counter/",
        "method": "POST",
        "endpoint": "/api/v1/tools/word-counter/run",
        "schema_url": "/api/v1/tools/word-counter",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "transform_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/word-counter/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/word-counter/"
    },
    {
      "id": "word-frequency",
      "category": "text-tools",
      "built": true,
      "requirements": "Token rules, locale, stop-word options and CSV export; no universal readability claims.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/word-frequency/run",
      "api": {
        "id": "word-frequency",
        "name": "Word frequency",
        "category": "text-tools",
        "description": "Count word occurrences, starting with the most frequent.",
        "notes": "",
        "human_path": "/en/text-tools/word-frequency/",
        "method": "POST",
        "endpoint": "/api/v1/tools/word-frequency/run",
        "schema_url": "/api/v1/tools/word-frequency",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/word-frequency/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/word-frequency/"
    },
    {
      "id": "wrap-text",
      "category": "text-tools",
      "built": true,
      "requirements": "Character width, word preservation and long-token behavior; downloadable plain text.",
      "implementation": {
        "fields": [
          {
            "key": "n",
            "label": "Maximum line width",
            "value": 80,
            "type": "number"
          }
        ],
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Hello world!",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/wrap-text/run",
      "api": {
        "id": "wrap-text",
        "name": "Wrap text",
        "category": "text-tools",
        "description": "Wrap text at word boundaries.",
        "notes": "",
        "human_path": "/en/text-tools/wrap-text/",
        "method": "POST",
        "endpoint": "/api/v1/tools/wrap-text/run",
        "schema_url": "/api/v1/tools/wrap-text",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "n": {
                  "type": "number",
                  "description": "Maximum line width",
                  "default": 80.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/text-tools/wrap-text/",
      "agent_url": "https://happytails.ai/agents/en/text-tools/wrap-text/"
    },
    {
      "id": "angle",
      "category": "unit-converters",
      "built": true,
      "requirements": "Degrees/radians/turns with exact-pi display where helpful.",
      "implementation": {
        "fields": [
          {
            "key": "value",
            "label": "Value",
            "value": 1,
            "type": "number"
          },
          {
            "key": "from",
            "label": "From",
            "value": "degree",
            "type": "select",
            "values": [
              "degree",
              "radian",
              "turn"
            ],
            "labels": {
              "m": "Meters (m)",
              "km": "Kilometers (km)",
              "cm": "Centimeters (cm)",
              "mm": "Millimeters (mm)",
              "in": "Inches (in)",
              "ft": "Feet (ft)",
              "yd": "Yards (yd)",
              "mi": "Miles (mi)",
              "kg": "Kilograms (kg)",
              "g": "Grams (g)",
              "mg": "Milligrams (mg)",
              "lb": "Pounds (lb)",
              "oz": "Ounces (oz)",
              "tonne": "Metric tonnes",
              "m²": "Square meters (m²)",
              "km²": "Square kilometers (km²)",
              "cm²": "Square centimeters (cm²)",
              "ft²": "Square feet (ft²)",
              "in²": "Square inches (in²)",
              "L": "Liters (L)",
              "mL": "Milliliters (mL)",
              "m³": "Cubic meters (m³)",
              "US fl oz": "US fluid ounces",
              "m/s": "Meters per second (m/s)",
              "km/h": "Kilometers per hour (km/h)",
              "mph": "Miles per hour (mph)",
              "knot": "Knots",
              "kB": "Kilobytes (kB, 1,000 bytes)",
              "MB": "Megabytes (MB, 1,000,000 bytes)",
              "GB": "Gigabytes (GB, decimal)",
              "TB": "Terabytes (TB, decimal)",
              "KiB": "Kibibytes (KiB, 1,024 bytes)",
              "MiB": "Mebibytes (MiB, 1,048,576 bytes)",
              "GiB": "Gibibytes (GiB, binary)",
              "TiB": "Tebibytes (TiB, binary)",
              "Pa": "Pascals (Pa)",
              "kPa": "Kilopascals (kPa)",
              "atm": "Standard atmospheres (atm)",
              "psi": "Pounds per square inch (psi)",
              "J": "Joules (J)",
              "kJ": "Kilojoules (kJ)",
              "cal": "Thermochemical calories (cal)",
              "kcal": "Kilocalories (kcal)",
              "Wh": "Watt-hours (Wh)",
              "kWh": "Kilowatt-hours (kWh)",
              "W": "Watts (W)",
              "kW": "Kilowatts (kW)",
              "MW": "Megawatts (MW)",
              "hp": "Mechanical horsepower (hp)"
            }
          },
          {
            "key": "to",
            "label": "To",
            "value": "radian",
            "type": "select",
            "values": [
              "degree",
              "radian",
              "turn"
            ],
            "labels": {
              "m": "Meters (m)",
              "km": "Kilometers (km)",
              "cm": "Centimeters (cm)",
              "mm": "Millimeters (mm)",
              "in": "Inches (in)",
              "ft": "Feet (ft)",
              "yd": "Yards (yd)",
              "mi": "Miles (mi)",
              "kg": "Kilograms (kg)",
              "g": "Grams (g)",
              "mg": "Milligrams (mg)",
              "lb": "Pounds (lb)",
              "oz": "Ounces (oz)",
              "tonne": "Metric tonnes",
              "m²": "Square meters (m²)",
              "km²": "Square kilometers (km²)",
              "cm²": "Square centimeters (cm²)",
              "ft²": "Square feet (ft²)",
              "in²": "Square inches (in²)",
              "L": "Liters (L)",
              "mL": "Milliliters (mL)",
              "m³": "Cubic meters (m³)",
              "US fl oz": "US fluid ounces",
              "m/s": "Meters per second (m/s)",
              "km/h": "Kilometers per hour (km/h)",
              "mph": "Miles per hour (mph)",
              "knot": "Knots",
              "kB": "Kilobytes (kB, 1,000 bytes)",
              "MB": "Megabytes (MB, 1,000,000 bytes)",
              "GB": "Gigabytes (GB, decimal)",
              "TB": "Terabytes (TB, decimal)",
              "KiB": "Kibibytes (KiB, 1,024 bytes)",
              "MiB": "Mebibytes (MiB, 1,048,576 bytes)",
              "GiB": "Gibibytes (GiB, binary)",
              "TiB": "Tebibytes (TiB, binary)",
              "Pa": "Pascals (Pa)",
              "kPa": "Kilopascals (kPa)",
              "atm": "Standard atmospheres (atm)",
              "psi": "Pounds per square inch (psi)",
              "J": "Joules (J)",
              "kJ": "Kilojoules (kJ)",
              "cal": "Thermochemical calories (cal)",
              "kcal": "Kilocalories (kcal)",
              "Wh": "Watt-hours (Wh)",
              "kWh": "Kilowatt-hours (kWh)",
              "W": "Watts (W)",
              "kW": "Kilowatts (kW)",
              "MW": "Megawatts (MW)",
              "hp": "Mechanical horsepower (hp)"
            }
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/angle/run",
      "api": {
        "id": "angle",
        "name": "Angle",
        "category": "unit-converters",
        "description": "Convert between degrees, radians, and turns.",
        "notes": "",
        "human_path": "/en/unit-converters/angle/",
        "method": "POST",
        "endpoint": "/api/v1/tools/angle/run",
        "schema_url": "/api/v1/tools/angle",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "value": {
                  "type": "number",
                  "description": "Value",
                  "default": 1.0
                },
                "from": {
                  "type": "string",
                  "description": "From",
                  "default": "degree",
                  "enum": [
                    "degree",
                    "radian",
                    "turn"
                  ]
                },
                "to": {
                  "type": "string",
                  "description": "To",
                  "default": "radian",
                  "enum": [
                    "degree",
                    "radian",
                    "turn"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/unit-converters/angle/",
      "agent_url": "https://happytails.ai/agents/en/unit-converters/angle/"
    },
    {
      "id": "area",
      "category": "unit-converters",
      "built": true,
      "requirements": "Squared conversion factors, acres/hectares and precision; no linear factor reuse.",
      "implementation": {
        "fields": [
          {
            "key": "value",
            "label": "Value",
            "value": 1,
            "type": "number"
          },
          {
            "key": "from",
            "label": "From",
            "value": "m²",
            "type": "select",
            "values": [
              "m²",
              "km²",
              "cm²",
              "ft²",
              "in²",
              "acre",
              "hectare"
            ],
            "labels": {
              "m": "Meters (m)",
              "km": "Kilometers (km)",
              "cm": "Centimeters (cm)",
              "mm": "Millimeters (mm)",
              "in": "Inches (in)",
              "ft": "Feet (ft)",
              "yd": "Yards (yd)",
              "mi": "Miles (mi)",
              "kg": "Kilograms (kg)",
              "g": "Grams (g)",
              "mg": "Milligrams (mg)",
              "lb": "Pounds (lb)",
              "oz": "Ounces (oz)",
              "tonne": "Metric tonnes",
              "m²": "Square meters (m²)",
              "km²": "Square kilometers (km²)",
              "cm²": "Square centimeters (cm²)",
              "ft²": "Square feet (ft²)",
              "in²": "Square inches (in²)",
              "L": "Liters (L)",
              "mL": "Milliliters (mL)",
              "m³": "Cubic meters (m³)",
              "US fl oz": "US fluid ounces",
              "m/s": "Meters per second (m/s)",
              "km/h": "Kilometers per hour (km/h)",
              "mph": "Miles per hour (mph)",
              "knot": "Knots",
              "kB": "Kilobytes (kB, 1,000 bytes)",
              "MB": "Megabytes (MB, 1,000,000 bytes)",
              "GB": "Gigabytes (GB, decimal)",
              "TB": "Terabytes (TB, decimal)",
              "KiB": "Kibibytes (KiB, 1,024 bytes)",
              "MiB": "Mebibytes (MiB, 1,048,576 bytes)",
              "GiB": "Gibibytes (GiB, binary)",
              "TiB": "Tebibytes (TiB, binary)",
              "Pa": "Pascals (Pa)",
              "kPa": "Kilopascals (kPa)",
              "atm": "Standard atmospheres (atm)",
              "psi": "Pounds per square inch (psi)",
              "J": "Joules (J)",
              "kJ": "Kilojoules (kJ)",
              "cal": "Thermochemical calories (cal)",
              "kcal": "Kilocalories (kcal)",
              "Wh": "Watt-hours (Wh)",
              "kWh": "Kilowatt-hours (kWh)",
              "W": "Watts (W)",
              "kW": "Kilowatts (kW)",
              "MW": "Megawatts (MW)",
              "hp": "Mechanical horsepower (hp)"
            }
          },
          {
            "key": "to",
            "label": "To",
            "value": "km²",
            "type": "select",
            "values": [
              "m²",
              "km²",
              "cm²",
              "ft²",
              "in²",
              "acre",
              "hectare"
            ],
            "labels": {
              "m": "Meters (m)",
              "km": "Kilometers (km)",
              "cm": "Centimeters (cm)",
              "mm": "Millimeters (mm)",
              "in": "Inches (in)",
              "ft": "Feet (ft)",
              "yd": "Yards (yd)",
              "mi": "Miles (mi)",
              "kg": "Kilograms (kg)",
              "g": "Grams (g)",
              "mg": "Milligrams (mg)",
              "lb": "Pounds (lb)",
              "oz": "Ounces (oz)",
              "tonne": "Metric tonnes",
              "m²": "Square meters (m²)",
              "km²": "Square kilometers (km²)",
              "cm²": "Square centimeters (cm²)",
              "ft²": "Square feet (ft²)",
              "in²": "Square inches (in²)",
              "L": "Liters (L)",
              "mL": "Milliliters (mL)",
              "m³": "Cubic meters (m³)",
              "US fl oz": "US fluid ounces",
              "m/s": "Meters per second (m/s)",
              "km/h": "Kilometers per hour (km/h)",
              "mph": "Miles per hour (mph)",
              "knot": "Knots",
              "kB": "Kilobytes (kB, 1,000 bytes)",
              "MB": "Megabytes (MB, 1,000,000 bytes)",
              "GB": "Gigabytes (GB, decimal)",
              "TB": "Terabytes (TB, decimal)",
              "KiB": "Kibibytes (KiB, 1,024 bytes)",
              "MiB": "Mebibytes (MiB, 1,048,576 bytes)",
              "GiB": "Gibibytes (GiB, binary)",
              "TiB": "Tebibytes (TiB, binary)",
              "Pa": "Pascals (Pa)",
              "kPa": "Kilopascals (kPa)",
              "atm": "Standard atmospheres (atm)",
              "psi": "Pounds per square inch (psi)",
              "J": "Joules (J)",
              "kJ": "Kilojoules (kJ)",
              "cal": "Thermochemical calories (cal)",
              "kcal": "Kilocalories (kcal)",
              "Wh": "Watt-hours (Wh)",
              "kWh": "Kilowatt-hours (kWh)",
              "W": "Watts (W)",
              "kW": "Kilowatts (kW)",
              "MW": "Megawatts (MW)",
              "hp": "Mechanical horsepower (hp)"
            }
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/area/run",
      "api": {
        "id": "area",
        "name": "Area",
        "category": "unit-converters",
        "description": "Convert between square meters, square feet, acres, and other area units.",
        "notes": "",
        "human_path": "/en/unit-converters/area/",
        "method": "POST",
        "endpoint": "/api/v1/tools/area/run",
        "schema_url": "/api/v1/tools/area",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "value": {
                  "type": "number",
                  "description": "Value",
                  "default": 1.0
                },
                "from": {
                  "type": "string",
                  "description": "From",
                  "default": "m²",
                  "enum": [
                    "m²",
                    "km²",
                    "cm²",
                    "ft²",
                    "in²",
                    "acre",
                    "hectare"
                  ]
                },
                "to": {
                  "type": "string",
                  "description": "To",
                  "default": "km²",
                  "enum": [
                    "m²",
                    "km²",
                    "cm²",
                    "ft²",
                    "in²",
                    "acre",
                    "hectare"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/unit-converters/area/",
      "agent_url": "https://happytails.ai/agents/en/unit-converters/area/"
    },
    {
      "id": "celsius-to-fahrenheit",
      "category": "unit-converters",
      "built": true,
      "requirements": "Direction-specific preset and reverse mode; explain affine conversion.",
      "implementation": {
        "fields": [
          {
            "key": "value",
            "label": "Celsius",
            "value": 20,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/celsius-to-fahrenheit/run",
      "api": {
        "id": "celsius-to-fahrenheit",
        "name": "Celsius to fahrenheit",
        "category": "unit-converters",
        "description": "Direction-specific preset and reverse mode.",
        "notes": "",
        "human_path": "/en/unit-converters/celsius-to-fahrenheit/",
        "method": "POST",
        "endpoint": "/api/v1/tools/celsius-to-fahrenheit/run",
        "schema_url": "/api/v1/tools/celsius-to-fahrenheit",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "value": {
                  "type": "number",
                  "description": "Celsius",
                  "default": 20.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/unit-converters/celsius-to-fahrenheit/",
      "agent_url": "https://happytails.ai/agents/en/unit-converters/celsius-to-fahrenheit/"
    },
    {
      "id": "cm-to-inches",
      "category": "unit-converters",
      "built": true,
      "requirements": "Preset cm/inches with decimal/fraction choices; show rounding clearly.",
      "implementation": {
        "fields": [
          {
            "key": "value",
            "label": "cm",
            "value": 1,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/cm-to-inches/run",
      "api": {
        "id": "cm-to-inches",
        "name": "Cm to inches",
        "category": "unit-converters",
        "description": "Preset cm/inches with decimal/fraction choices.",
        "notes": "",
        "human_path": "/en/unit-converters/cm-to-inches/",
        "method": "POST",
        "endpoint": "/api/v1/tools/cm-to-inches/run",
        "schema_url": "/api/v1/tools/cm-to-inches",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "value": {
                  "type": "number",
                  "description": "cm",
                  "default": 1.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/unit-converters/cm-to-inches/",
      "agent_url": "https://happytails.ai/agents/en/unit-converters/cm-to-inches/"
    },
    {
      "id": "data-storage",
      "category": "unit-converters",
      "built": true,
      "requirements": "Decimal SI versus binary IEC, bits versus bytes and unambiguous unit labels.",
      "implementation": {
        "fields": [
          {
            "key": "value",
            "label": "Value",
            "value": 1,
            "type": "number"
          },
          {
            "key": "from",
            "label": "From",
            "value": "byte",
            "type": "select",
            "values": [
              "byte",
              "bit",
              "kB",
              "MB",
              "GB",
              "TB",
              "KiB",
              "MiB",
              "GiB",
              "TiB"
            ],
            "labels": {
              "m": "Meters (m)",
              "km": "Kilometers (km)",
              "cm": "Centimeters (cm)",
              "mm": "Millimeters (mm)",
              "in": "Inches (in)",
              "ft": "Feet (ft)",
              "yd": "Yards (yd)",
              "mi": "Miles (mi)",
              "kg": "Kilograms (kg)",
              "g": "Grams (g)",
              "mg": "Milligrams (mg)",
              "lb": "Pounds (lb)",
              "oz": "Ounces (oz)",
              "tonne": "Metric tonnes",
              "m²": "Square meters (m²)",
              "km²": "Square kilometers (km²)",
              "cm²": "Square centimeters (cm²)",
              "ft²": "Square feet (ft²)",
              "in²": "Square inches (in²)",
              "L": "Liters (L)",
              "mL": "Milliliters (mL)",
              "m³": "Cubic meters (m³)",
              "US fl oz": "US fluid ounces",
              "m/s": "Meters per second (m/s)",
              "km/h": "Kilometers per hour (km/h)",
              "mph": "Miles per hour (mph)",
              "knot": "Knots",
              "kB": "Kilobytes (kB, 1,000 bytes)",
              "MB": "Megabytes (MB, 1,000,000 bytes)",
              "GB": "Gigabytes (GB, decimal)",
              "TB": "Terabytes (TB, decimal)",
              "KiB": "Kibibytes (KiB, 1,024 bytes)",
              "MiB": "Mebibytes (MiB, 1,048,576 bytes)",
              "GiB": "Gibibytes (GiB, binary)",
              "TiB": "Tebibytes (TiB, binary)",
              "Pa": "Pascals (Pa)",
              "kPa": "Kilopascals (kPa)",
              "atm": "Standard atmospheres (atm)",
              "psi": "Pounds per square inch (psi)",
              "J": "Joules (J)",
              "kJ": "Kilojoules (kJ)",
              "cal": "Thermochemical calories (cal)",
              "kcal": "Kilocalories (kcal)",
              "Wh": "Watt-hours (Wh)",
              "kWh": "Kilowatt-hours (kWh)",
              "W": "Watts (W)",
              "kW": "Kilowatts (kW)",
              "MW": "Megawatts (MW)",
              "hp": "Mechanical horsepower (hp)"
            }
          },
          {
            "key": "to",
            "label": "To",
            "value": "bit",
            "type": "select",
            "values": [
              "byte",
              "bit",
              "kB",
              "MB",
              "GB",
              "TB",
              "KiB",
              "MiB",
              "GiB",
              "TiB"
            ],
            "labels": {
              "m": "Meters (m)",
              "km": "Kilometers (km)",
              "cm": "Centimeters (cm)",
              "mm": "Millimeters (mm)",
              "in": "Inches (in)",
              "ft": "Feet (ft)",
              "yd": "Yards (yd)",
              "mi": "Miles (mi)",
              "kg": "Kilograms (kg)",
              "g": "Grams (g)",
              "mg": "Milligrams (mg)",
              "lb": "Pounds (lb)",
              "oz": "Ounces (oz)",
              "tonne": "Metric tonnes",
              "m²": "Square meters (m²)",
              "km²": "Square kilometers (km²)",
              "cm²": "Square centimeters (cm²)",
              "ft²": "Square feet (ft²)",
              "in²": "Square inches (in²)",
              "L": "Liters (L)",
              "mL": "Milliliters (mL)",
              "m³": "Cubic meters (m³)",
              "US fl oz": "US fluid ounces",
              "m/s": "Meters per second (m/s)",
              "km/h": "Kilometers per hour (km/h)",
              "mph": "Miles per hour (mph)",
              "knot": "Knots",
              "kB": "Kilobytes (kB, 1,000 bytes)",
              "MB": "Megabytes (MB, 1,000,000 bytes)",
              "GB": "Gigabytes (GB, decimal)",
              "TB": "Terabytes (TB, decimal)",
              "KiB": "Kibibytes (KiB, 1,024 bytes)",
              "MiB": "Mebibytes (MiB, 1,048,576 bytes)",
              "GiB": "Gibibytes (GiB, binary)",
              "TiB": "Tebibytes (TiB, binary)",
              "Pa": "Pascals (Pa)",
              "kPa": "Kilopascals (kPa)",
              "atm": "Standard atmospheres (atm)",
              "psi": "Pounds per square inch (psi)",
              "J": "Joules (J)",
              "kJ": "Kilojoules (kJ)",
              "cal": "Thermochemical calories (cal)",
              "kcal": "Kilocalories (kcal)",
              "Wh": "Watt-hours (Wh)",
              "kWh": "Kilowatt-hours (kWh)",
              "W": "Watts (W)",
              "kW": "Kilowatts (kW)",
              "MW": "Megawatts (MW)",
              "hp": "Mechanical horsepower (hp)"
            }
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/data-storage/run",
      "api": {
        "id": "data-storage",
        "name": "Data storage",
        "category": "unit-converters",
        "description": "Convert between bits, bytes, decimal storage units, and binary storage units.",
        "notes": "",
        "human_path": "/en/unit-converters/data-storage/",
        "method": "POST",
        "endpoint": "/api/v1/tools/data-storage/run",
        "schema_url": "/api/v1/tools/data-storage",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "value": {
                  "type": "number",
                  "description": "Value",
                  "default": 1.0
                },
                "from": {
                  "type": "string",
                  "description": "From",
                  "default": "byte",
                  "enum": [
                    "byte",
                    "bit",
                    "kB",
                    "MB",
                    "GB",
                    "TB",
                    "KiB",
                    "MiB",
                    "GiB",
                    "TiB"
                  ]
                },
                "to": {
                  "type": "string",
                  "description": "To",
                  "default": "bit",
                  "enum": [
                    "byte",
                    "bit",
                    "kB",
                    "MB",
                    "GB",
                    "TB",
                    "KiB",
                    "MiB",
                    "GiB",
                    "TiB"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/unit-converters/data-storage/",
      "agent_url": "https://happytails.ai/agents/en/unit-converters/data-storage/"
    },
    {
      "id": "energy",
      "category": "unit-converters",
      "built": true,
      "requirements": "Clear joule/calorie/kWh definitions and precision.",
      "implementation": {
        "fields": [
          {
            "key": "value",
            "label": "Value",
            "value": 1,
            "type": "number"
          },
          {
            "key": "from",
            "label": "From",
            "value": "J",
            "type": "select",
            "values": [
              "J",
              "kJ",
              "cal",
              "kcal",
              "Wh",
              "kWh"
            ],
            "labels": {
              "m": "Meters (m)",
              "km": "Kilometers (km)",
              "cm": "Centimeters (cm)",
              "mm": "Millimeters (mm)",
              "in": "Inches (in)",
              "ft": "Feet (ft)",
              "yd": "Yards (yd)",
              "mi": "Miles (mi)",
              "kg": "Kilograms (kg)",
              "g": "Grams (g)",
              "mg": "Milligrams (mg)",
              "lb": "Pounds (lb)",
              "oz": "Ounces (oz)",
              "tonne": "Metric tonnes",
              "m²": "Square meters (m²)",
              "km²": "Square kilometers (km²)",
              "cm²": "Square centimeters (cm²)",
              "ft²": "Square feet (ft²)",
              "in²": "Square inches (in²)",
              "L": "Liters (L)",
              "mL": "Milliliters (mL)",
              "m³": "Cubic meters (m³)",
              "US fl oz": "US fluid ounces",
              "m/s": "Meters per second (m/s)",
              "km/h": "Kilometers per hour (km/h)",
              "mph": "Miles per hour (mph)",
              "knot": "Knots",
              "kB": "Kilobytes (kB, 1,000 bytes)",
              "MB": "Megabytes (MB, 1,000,000 bytes)",
              "GB": "Gigabytes (GB, decimal)",
              "TB": "Terabytes (TB, decimal)",
              "KiB": "Kibibytes (KiB, 1,024 bytes)",
              "MiB": "Mebibytes (MiB, 1,048,576 bytes)",
              "GiB": "Gibibytes (GiB, binary)",
              "TiB": "Tebibytes (TiB, binary)",
              "Pa": "Pascals (Pa)",
              "kPa": "Kilopascals (kPa)",
              "atm": "Standard atmospheres (atm)",
              "psi": "Pounds per square inch (psi)",
              "J": "Joules (J)",
              "kJ": "Kilojoules (kJ)",
              "cal": "Thermochemical calories (cal)",
              "kcal": "Kilocalories (kcal)",
              "Wh": "Watt-hours (Wh)",
              "kWh": "Kilowatt-hours (kWh)",
              "W": "Watts (W)",
              "kW": "Kilowatts (kW)",
              "MW": "Megawatts (MW)",
              "hp": "Mechanical horsepower (hp)"
            }
          },
          {
            "key": "to",
            "label": "To",
            "value": "kJ",
            "type": "select",
            "values": [
              "J",
              "kJ",
              "cal",
              "kcal",
              "Wh",
              "kWh"
            ],
            "labels": {
              "m": "Meters (m)",
              "km": "Kilometers (km)",
              "cm": "Centimeters (cm)",
              "mm": "Millimeters (mm)",
              "in": "Inches (in)",
              "ft": "Feet (ft)",
              "yd": "Yards (yd)",
              "mi": "Miles (mi)",
              "kg": "Kilograms (kg)",
              "g": "Grams (g)",
              "mg": "Milligrams (mg)",
              "lb": "Pounds (lb)",
              "oz": "Ounces (oz)",
              "tonne": "Metric tonnes",
              "m²": "Square meters (m²)",
              "km²": "Square kilometers (km²)",
              "cm²": "Square centimeters (cm²)",
              "ft²": "Square feet (ft²)",
              "in²": "Square inches (in²)",
              "L": "Liters (L)",
              "mL": "Milliliters (mL)",
              "m³": "Cubic meters (m³)",
              "US fl oz": "US fluid ounces",
              "m/s": "Meters per second (m/s)",
              "km/h": "Kilometers per hour (km/h)",
              "mph": "Miles per hour (mph)",
              "knot": "Knots",
              "kB": "Kilobytes (kB, 1,000 bytes)",
              "MB": "Megabytes (MB, 1,000,000 bytes)",
              "GB": "Gigabytes (GB, decimal)",
              "TB": "Terabytes (TB, decimal)",
              "KiB": "Kibibytes (KiB, 1,024 bytes)",
              "MiB": "Mebibytes (MiB, 1,048,576 bytes)",
              "GiB": "Gibibytes (GiB, binary)",
              "TiB": "Tebibytes (TiB, binary)",
              "Pa": "Pascals (Pa)",
              "kPa": "Kilopascals (kPa)",
              "atm": "Standard atmospheres (atm)",
              "psi": "Pounds per square inch (psi)",
              "J": "Joules (J)",
              "kJ": "Kilojoules (kJ)",
              "cal": "Thermochemical calories (cal)",
              "kcal": "Kilocalories (kcal)",
              "Wh": "Watt-hours (Wh)",
              "kWh": "Kilowatt-hours (kWh)",
              "W": "Watts (W)",
              "kW": "Kilowatts (kW)",
              "MW": "Megawatts (MW)",
              "hp": "Mechanical horsepower (hp)"
            }
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/energy/run",
      "api": {
        "id": "energy",
        "name": "Energy",
        "category": "unit-converters",
        "description": "Convert between joules, calories, watt-hours, and kilowatt-hours.",
        "notes": "",
        "human_path": "/en/unit-converters/energy/",
        "method": "POST",
        "endpoint": "/api/v1/tools/energy/run",
        "schema_url": "/api/v1/tools/energy",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "value": {
                  "type": "number",
                  "description": "Value",
                  "default": 1.0
                },
                "from": {
                  "type": "string",
                  "description": "From",
                  "default": "J",
                  "enum": [
                    "J",
                    "kJ",
                    "cal",
                    "kcal",
                    "Wh",
                    "kWh"
                  ]
                },
                "to": {
                  "type": "string",
                  "description": "To",
                  "default": "kJ",
                  "enum": [
                    "J",
                    "kJ",
                    "cal",
                    "kcal",
                    "Wh",
                    "kWh"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/unit-converters/energy/",
      "agent_url": "https://happytails.ai/agents/en/unit-converters/energy/"
    },
    {
      "id": "fahrenheit-to-celsius",
      "category": "unit-converters",
      "built": true,
      "requirements": "Direction-specific examples and reverse mode; no arbitrary numeric URLs.",
      "implementation": {
        "fields": [
          {
            "key": "value",
            "label": "Fahrenheit",
            "value": 68,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/fahrenheit-to-celsius/run",
      "api": {
        "id": "fahrenheit-to-celsius",
        "name": "Fahrenheit to celsius",
        "category": "unit-converters",
        "description": "Direction-specific examples and reverse mode.",
        "notes": "",
        "human_path": "/en/unit-converters/fahrenheit-to-celsius/",
        "method": "POST",
        "endpoint": "/api/v1/tools/fahrenheit-to-celsius/run",
        "schema_url": "/api/v1/tools/fahrenheit-to-celsius",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "value": {
                  "type": "number",
                  "description": "Fahrenheit",
                  "default": 68.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/unit-converters/fahrenheit-to-celsius/",
      "agent_url": "https://happytails.ai/agents/en/unit-converters/fahrenheit-to-celsius/"
    },
    {
      "id": "grams-to-ounces",
      "category": "unit-converters",
      "built": true,
      "requirements": "Distinguish avoirdupois from troy ounces; no mass-to-volume assumption.",
      "implementation": {
        "fields": [
          {
            "key": "value",
            "label": "g",
            "value": 1,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/grams-to-ounces/run",
      "api": {
        "id": "grams-to-ounces",
        "name": "Grams to ounces",
        "category": "unit-converters",
        "description": "Distinguish avoirdupois from troy ounces.",
        "notes": "",
        "human_path": "/en/unit-converters/grams-to-ounces/",
        "method": "POST",
        "endpoint": "/api/v1/tools/grams-to-ounces/run",
        "schema_url": "/api/v1/tools/grams-to-ounces",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "value": {
                  "type": "number",
                  "description": "g",
                  "default": 1.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/unit-converters/grams-to-ounces/",
      "agent_url": "https://happytails.ai/agents/en/unit-converters/grams-to-ounces/"
    },
    {
      "id": "inches-to-cm",
      "category": "unit-converters",
      "built": true,
      "requirements": "Decimal/fraction input and explicit output rounding.",
      "implementation": {
        "fields": [
          {
            "key": "value",
            "label": "in",
            "value": 1,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/inches-to-cm/run",
      "api": {
        "id": "inches-to-cm",
        "name": "Inches to cm",
        "category": "unit-converters",
        "description": "Decimal/fraction input and explicit output rounding.",
        "notes": "",
        "human_path": "/en/unit-converters/inches-to-cm/",
        "method": "POST",
        "endpoint": "/api/v1/tools/inches-to-cm/run",
        "schema_url": "/api/v1/tools/inches-to-cm",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "value": {
                  "type": "number",
                  "description": "in",
                  "default": 1.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/unit-converters/inches-to-cm/",
      "agent_url": "https://happytails.ai/agents/en/unit-converters/inches-to-cm/"
    },
    {
      "id": "kg-to-lb",
      "category": "unit-converters",
      "built": true,
      "requirements": "Preset kg/lb direction, reciprocal input and precision; do not spawn numeric-value pages.",
      "implementation": {
        "fields": [
          {
            "key": "value",
            "label": "kg",
            "value": 1,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/kg-to-lb/run",
      "api": {
        "id": "kg-to-lb",
        "name": "Kg to lb",
        "category": "unit-converters",
        "description": "Preset kg/lb direction, reciprocal input and precision.",
        "notes": "",
        "human_path": "/en/unit-converters/kg-to-lb/",
        "method": "POST",
        "endpoint": "/api/v1/tools/kg-to-lb/run",
        "schema_url": "/api/v1/tools/kg-to-lb",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "value": {
                  "type": "number",
                  "description": "kg",
                  "default": 1.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/unit-converters/kg-to-lb/",
      "agent_url": "https://happytails.ai/agents/en/unit-converters/kg-to-lb/"
    },
    {
      "id": "km-to-miles",
      "category": "unit-converters",
      "built": true,
      "requirements": "Use international mile; give reverse mode and useful examples.",
      "implementation": {
        "fields": [
          {
            "key": "value",
            "label": "km",
            "value": 1,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/km-to-miles/run",
      "api": {
        "id": "km-to-miles",
        "name": "Km to miles",
        "category": "unit-converters",
        "description": "Use international mile.",
        "notes": "",
        "human_path": "/en/unit-converters/km-to-miles/",
        "method": "POST",
        "endpoint": "/api/v1/tools/km-to-miles/run",
        "schema_url": "/api/v1/tools/km-to-miles",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "value": {
                  "type": "number",
                  "description": "km",
                  "default": 1.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/unit-converters/km-to-miles/",
      "agent_url": "https://happytails.ai/agents/en/unit-converters/km-to-miles/"
    },
    {
      "id": "lbs-to-kg",
      "category": "unit-converters",
      "built": true,
      "requirements": "Direction-specific input and examples with verified constant.",
      "implementation": {
        "fields": [
          {
            "key": "value",
            "label": "lb",
            "value": 1,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/lbs-to-kg/run",
      "api": {
        "id": "lbs-to-kg",
        "name": "Lbs to kg",
        "category": "unit-converters",
        "description": "Direction-specific input and examples with verified constant.",
        "notes": "",
        "human_path": "/en/unit-converters/lbs-to-kg/",
        "method": "POST",
        "endpoint": "/api/v1/tools/lbs-to-kg/run",
        "schema_url": "/api/v1/tools/lbs-to-kg",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "value": {
                  "type": "number",
                  "description": "lb",
                  "default": 1.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/unit-converters/lbs-to-kg/",
      "agent_url": "https://happytails.ai/agents/en/unit-converters/lbs-to-kg/"
    },
    {
      "id": "length",
      "category": "unit-converters",
      "built": true,
      "requirements": "Selectable units and supported precision; central length hub links to researched pair tools.",
      "implementation": {
        "fields": [
          {
            "key": "value",
            "label": "Value",
            "value": 1,
            "type": "number"
          },
          {
            "key": "from",
            "label": "From",
            "value": "m",
            "type": "select",
            "values": [
              "m",
              "km",
              "cm",
              "mm",
              "in",
              "ft",
              "yd",
              "mi"
            ],
            "labels": {
              "m": "Meters (m)",
              "km": "Kilometers (km)",
              "cm": "Centimeters (cm)",
              "mm": "Millimeters (mm)",
              "in": "Inches (in)",
              "ft": "Feet (ft)",
              "yd": "Yards (yd)",
              "mi": "Miles (mi)",
              "kg": "Kilograms (kg)",
              "g": "Grams (g)",
              "mg": "Milligrams (mg)",
              "lb": "Pounds (lb)",
              "oz": "Ounces (oz)",
              "tonne": "Metric tonnes",
              "m²": "Square meters (m²)",
              "km²": "Square kilometers (km²)",
              "cm²": "Square centimeters (cm²)",
              "ft²": "Square feet (ft²)",
              "in²": "Square inches (in²)",
              "L": "Liters (L)",
              "mL": "Milliliters (mL)",
              "m³": "Cubic meters (m³)",
              "US fl oz": "US fluid ounces",
              "m/s": "Meters per second (m/s)",
              "km/h": "Kilometers per hour (km/h)",
              "mph": "Miles per hour (mph)",
              "knot": "Knots",
              "kB": "Kilobytes (kB, 1,000 bytes)",
              "MB": "Megabytes (MB, 1,000,000 bytes)",
              "GB": "Gigabytes (GB, decimal)",
              "TB": "Terabytes (TB, decimal)",
              "KiB": "Kibibytes (KiB, 1,024 bytes)",
              "MiB": "Mebibytes (MiB, 1,048,576 bytes)",
              "GiB": "Gibibytes (GiB, binary)",
              "TiB": "Tebibytes (TiB, binary)",
              "Pa": "Pascals (Pa)",
              "kPa": "Kilopascals (kPa)",
              "atm": "Standard atmospheres (atm)",
              "psi": "Pounds per square inch (psi)",
              "J": "Joules (J)",
              "kJ": "Kilojoules (kJ)",
              "cal": "Thermochemical calories (cal)",
              "kcal": "Kilocalories (kcal)",
              "Wh": "Watt-hours (Wh)",
              "kWh": "Kilowatt-hours (kWh)",
              "W": "Watts (W)",
              "kW": "Kilowatts (kW)",
              "MW": "Megawatts (MW)",
              "hp": "Mechanical horsepower (hp)"
            }
          },
          {
            "key": "to",
            "label": "To",
            "value": "km",
            "type": "select",
            "values": [
              "m",
              "km",
              "cm",
              "mm",
              "in",
              "ft",
              "yd",
              "mi"
            ],
            "labels": {
              "m": "Meters (m)",
              "km": "Kilometers (km)",
              "cm": "Centimeters (cm)",
              "mm": "Millimeters (mm)",
              "in": "Inches (in)",
              "ft": "Feet (ft)",
              "yd": "Yards (yd)",
              "mi": "Miles (mi)",
              "kg": "Kilograms (kg)",
              "g": "Grams (g)",
              "mg": "Milligrams (mg)",
              "lb": "Pounds (lb)",
              "oz": "Ounces (oz)",
              "tonne": "Metric tonnes",
              "m²": "Square meters (m²)",
              "km²": "Square kilometers (km²)",
              "cm²": "Square centimeters (cm²)",
              "ft²": "Square feet (ft²)",
              "in²": "Square inches (in²)",
              "L": "Liters (L)",
              "mL": "Milliliters (mL)",
              "m³": "Cubic meters (m³)",
              "US fl oz": "US fluid ounces",
              "m/s": "Meters per second (m/s)",
              "km/h": "Kilometers per hour (km/h)",
              "mph": "Miles per hour (mph)",
              "knot": "Knots",
              "kB": "Kilobytes (kB, 1,000 bytes)",
              "MB": "Megabytes (MB, 1,000,000 bytes)",
              "GB": "Gigabytes (GB, decimal)",
              "TB": "Terabytes (TB, decimal)",
              "KiB": "Kibibytes (KiB, 1,024 bytes)",
              "MiB": "Mebibytes (MiB, 1,048,576 bytes)",
              "GiB": "Gibibytes (GiB, binary)",
              "TiB": "Tebibytes (TiB, binary)",
              "Pa": "Pascals (Pa)",
              "kPa": "Kilopascals (kPa)",
              "atm": "Standard atmospheres (atm)",
              "psi": "Pounds per square inch (psi)",
              "J": "Joules (J)",
              "kJ": "Kilojoules (kJ)",
              "cal": "Thermochemical calories (cal)",
              "kcal": "Kilocalories (kcal)",
              "Wh": "Watt-hours (Wh)",
              "kWh": "Kilowatt-hours (kWh)",
              "W": "Watts (W)",
              "kW": "Kilowatts (kW)",
              "MW": "Megawatts (MW)",
              "hp": "Mechanical horsepower (hp)"
            }
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/length/run",
      "api": {
        "id": "length",
        "name": "Length",
        "category": "unit-converters",
        "description": "Convert between meters, feet, inches, and other length units.",
        "notes": "",
        "human_path": "/en/unit-converters/length/",
        "method": "POST",
        "endpoint": "/api/v1/tools/length/run",
        "schema_url": "/api/v1/tools/length",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "value": {
                  "type": "number",
                  "description": "Value",
                  "default": 1.0
                },
                "from": {
                  "type": "string",
                  "description": "From",
                  "default": "m",
                  "enum": [
                    "m",
                    "km",
                    "cm",
                    "mm",
                    "in",
                    "ft",
                    "yd",
                    "mi"
                  ]
                },
                "to": {
                  "type": "string",
                  "description": "To",
                  "default": "km",
                  "enum": [
                    "m",
                    "km",
                    "cm",
                    "mm",
                    "in",
                    "ft",
                    "yd",
                    "mi"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/unit-converters/length/",
      "agent_url": "https://happytails.ai/agents/en/unit-converters/length/"
    },
    {
      "id": "liters-to-gallons",
      "category": "unit-converters",
      "built": true,
      "requirements": "US liquid versus Imperial gallon selector visible by default.",
      "implementation": {
        "fields": [
          {
            "key": "value",
            "label": "L",
            "value": 1,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/liters-to-gallons/run",
      "api": {
        "id": "liters-to-gallons",
        "name": "Liters to gallons",
        "category": "unit-converters",
        "description": "US liquid versus Imperial gallon selector visible by default.",
        "notes": "",
        "human_path": "/en/unit-converters/liters-to-gallons/",
        "method": "POST",
        "endpoint": "/api/v1/tools/liters-to-gallons/run",
        "schema_url": "/api/v1/tools/liters-to-gallons",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "value": {
                  "type": "number",
                  "description": "L",
                  "default": 1.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/unit-converters/liters-to-gallons/",
      "agent_url": "https://happytails.ai/agents/en/unit-converters/liters-to-gallons/"
    },
    {
      "id": "meters-to-feet",
      "category": "unit-converters",
      "built": true,
      "requirements": "Decimal feet versus feet-and-inches outputs explicitly separated.",
      "implementation": {
        "fields": [
          {
            "key": "value",
            "label": "m",
            "value": 1,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/meters-to-feet/run",
      "api": {
        "id": "meters-to-feet",
        "name": "Meters to feet",
        "category": "unit-converters",
        "description": "Decimal feet versus feet-and-inches outputs explicitly separated.",
        "notes": "",
        "human_path": "/en/unit-converters/meters-to-feet/",
        "method": "POST",
        "endpoint": "/api/v1/tools/meters-to-feet/run",
        "schema_url": "/api/v1/tools/meters-to-feet",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "value": {
                  "type": "number",
                  "description": "m",
                  "default": 1.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/unit-converters/meters-to-feet/",
      "agent_url": "https://happytails.ai/agents/en/unit-converters/meters-to-feet/"
    },
    {
      "id": "mm-to-inches",
      "category": "unit-converters",
      "built": true,
      "requirements": "Decimal/fractional inches and precision controls.",
      "implementation": {
        "fields": [
          {
            "key": "value",
            "label": "mm",
            "value": 1,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/mm-to-inches/run",
      "api": {
        "id": "mm-to-inches",
        "name": "Mm to inches",
        "category": "unit-converters",
        "description": "Decimal/fractional inches and precision controls.",
        "notes": "",
        "human_path": "/en/unit-converters/mm-to-inches/",
        "method": "POST",
        "endpoint": "/api/v1/tools/mm-to-inches/run",
        "schema_url": "/api/v1/tools/mm-to-inches",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "value": {
                  "type": "number",
                  "description": "mm",
                  "default": 1.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/unit-converters/mm-to-inches/",
      "agent_url": "https://happytails.ai/agents/en/unit-converters/mm-to-inches/"
    },
    {
      "id": "mph-to-kmh",
      "category": "unit-converters",
      "built": true,
      "requirements": "Preset speed direction and consistent decimal precision.",
      "implementation": {
        "fields": [
          {
            "key": "value",
            "label": "mph",
            "value": 1,
            "type": "number"
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/mph-to-kmh/run",
      "api": {
        "id": "mph-to-kmh",
        "name": "Mph to kmh",
        "category": "unit-converters",
        "description": "Preset speed direction and consistent decimal precision.",
        "notes": "",
        "human_path": "/en/unit-converters/mph-to-kmh/",
        "method": "POST",
        "endpoint": "/api/v1/tools/mph-to-kmh/run",
        "schema_url": "/api/v1/tools/mph-to-kmh",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "value": {
                  "type": "number",
                  "description": "mph",
                  "default": 1.0
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/unit-converters/mph-to-kmh/",
      "agent_url": "https://happytails.ai/agents/en/unit-converters/mph-to-kmh/"
    },
    {
      "id": "power",
      "category": "unit-converters",
      "built": true,
      "requirements": "Specify horsepower convention and verified constants.",
      "implementation": {
        "fields": [
          {
            "key": "value",
            "label": "Value",
            "value": 1,
            "type": "number"
          },
          {
            "key": "from",
            "label": "From",
            "value": "W",
            "type": "select",
            "values": [
              "W",
              "kW",
              "MW",
              "hp"
            ],
            "labels": {
              "m": "Meters (m)",
              "km": "Kilometers (km)",
              "cm": "Centimeters (cm)",
              "mm": "Millimeters (mm)",
              "in": "Inches (in)",
              "ft": "Feet (ft)",
              "yd": "Yards (yd)",
              "mi": "Miles (mi)",
              "kg": "Kilograms (kg)",
              "g": "Grams (g)",
              "mg": "Milligrams (mg)",
              "lb": "Pounds (lb)",
              "oz": "Ounces (oz)",
              "tonne": "Metric tonnes",
              "m²": "Square meters (m²)",
              "km²": "Square kilometers (km²)",
              "cm²": "Square centimeters (cm²)",
              "ft²": "Square feet (ft²)",
              "in²": "Square inches (in²)",
              "L": "Liters (L)",
              "mL": "Milliliters (mL)",
              "m³": "Cubic meters (m³)",
              "US fl oz": "US fluid ounces",
              "m/s": "Meters per second (m/s)",
              "km/h": "Kilometers per hour (km/h)",
              "mph": "Miles per hour (mph)",
              "knot": "Knots",
              "kB": "Kilobytes (kB, 1,000 bytes)",
              "MB": "Megabytes (MB, 1,000,000 bytes)",
              "GB": "Gigabytes (GB, decimal)",
              "TB": "Terabytes (TB, decimal)",
              "KiB": "Kibibytes (KiB, 1,024 bytes)",
              "MiB": "Mebibytes (MiB, 1,048,576 bytes)",
              "GiB": "Gibibytes (GiB, binary)",
              "TiB": "Tebibytes (TiB, binary)",
              "Pa": "Pascals (Pa)",
              "kPa": "Kilopascals (kPa)",
              "atm": "Standard atmospheres (atm)",
              "psi": "Pounds per square inch (psi)",
              "J": "Joules (J)",
              "kJ": "Kilojoules (kJ)",
              "cal": "Thermochemical calories (cal)",
              "kcal": "Kilocalories (kcal)",
              "Wh": "Watt-hours (Wh)",
              "kWh": "Kilowatt-hours (kWh)",
              "W": "Watts (W)",
              "kW": "Kilowatts (kW)",
              "MW": "Megawatts (MW)",
              "hp": "Mechanical horsepower (hp)"
            }
          },
          {
            "key": "to",
            "label": "To",
            "value": "kW",
            "type": "select",
            "values": [
              "W",
              "kW",
              "MW",
              "hp"
            ],
            "labels": {
              "m": "Meters (m)",
              "km": "Kilometers (km)",
              "cm": "Centimeters (cm)",
              "mm": "Millimeters (mm)",
              "in": "Inches (in)",
              "ft": "Feet (ft)",
              "yd": "Yards (yd)",
              "mi": "Miles (mi)",
              "kg": "Kilograms (kg)",
              "g": "Grams (g)",
              "mg": "Milligrams (mg)",
              "lb": "Pounds (lb)",
              "oz": "Ounces (oz)",
              "tonne": "Metric tonnes",
              "m²": "Square meters (m²)",
              "km²": "Square kilometers (km²)",
              "cm²": "Square centimeters (cm²)",
              "ft²": "Square feet (ft²)",
              "in²": "Square inches (in²)",
              "L": "Liters (L)",
              "mL": "Milliliters (mL)",
              "m³": "Cubic meters (m³)",
              "US fl oz": "US fluid ounces",
              "m/s": "Meters per second (m/s)",
              "km/h": "Kilometers per hour (km/h)",
              "mph": "Miles per hour (mph)",
              "knot": "Knots",
              "kB": "Kilobytes (kB, 1,000 bytes)",
              "MB": "Megabytes (MB, 1,000,000 bytes)",
              "GB": "Gigabytes (GB, decimal)",
              "TB": "Terabytes (TB, decimal)",
              "KiB": "Kibibytes (KiB, 1,024 bytes)",
              "MiB": "Mebibytes (MiB, 1,048,576 bytes)",
              "GiB": "Gibibytes (GiB, binary)",
              "TiB": "Tebibytes (TiB, binary)",
              "Pa": "Pascals (Pa)",
              "kPa": "Kilopascals (kPa)",
              "atm": "Standard atmospheres (atm)",
              "psi": "Pounds per square inch (psi)",
              "J": "Joules (J)",
              "kJ": "Kilojoules (kJ)",
              "cal": "Thermochemical calories (cal)",
              "kcal": "Kilocalories (kcal)",
              "Wh": "Watt-hours (Wh)",
              "kWh": "Kilowatt-hours (kWh)",
              "W": "Watts (W)",
              "kW": "Kilowatts (kW)",
              "MW": "Megawatts (MW)",
              "hp": "Mechanical horsepower (hp)"
            }
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/power/run",
      "api": {
        "id": "power",
        "name": "Power",
        "category": "unit-converters",
        "description": "Convert between watts, kilowatts, megawatts, and horsepower.",
        "notes": "",
        "human_path": "/en/unit-converters/power/",
        "method": "POST",
        "endpoint": "/api/v1/tools/power/run",
        "schema_url": "/api/v1/tools/power",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "value": {
                  "type": "number",
                  "description": "Value",
                  "default": 1.0
                },
                "from": {
                  "type": "string",
                  "description": "From",
                  "default": "W",
                  "enum": [
                    "W",
                    "kW",
                    "MW",
                    "hp"
                  ]
                },
                "to": {
                  "type": "string",
                  "description": "To",
                  "default": "kW",
                  "enum": [
                    "W",
                    "kW",
                    "MW",
                    "hp"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/unit-converters/power/",
      "agent_url": "https://happytails.ai/agents/en/unit-converters/power/"
    },
    {
      "id": "pressure",
      "category": "unit-converters",
      "built": true,
      "requirements": "Define absolute versus gauge inputs when relevant; verified constants.",
      "implementation": {
        "fields": [
          {
            "key": "value",
            "label": "Value",
            "value": 1,
            "type": "number"
          },
          {
            "key": "from",
            "label": "From",
            "value": "Pa",
            "type": "select",
            "values": [
              "Pa",
              "kPa",
              "bar",
              "atm",
              "psi"
            ],
            "labels": {
              "m": "Meters (m)",
              "km": "Kilometers (km)",
              "cm": "Centimeters (cm)",
              "mm": "Millimeters (mm)",
              "in": "Inches (in)",
              "ft": "Feet (ft)",
              "yd": "Yards (yd)",
              "mi": "Miles (mi)",
              "kg": "Kilograms (kg)",
              "g": "Grams (g)",
              "mg": "Milligrams (mg)",
              "lb": "Pounds (lb)",
              "oz": "Ounces (oz)",
              "tonne": "Metric tonnes",
              "m²": "Square meters (m²)",
              "km²": "Square kilometers (km²)",
              "cm²": "Square centimeters (cm²)",
              "ft²": "Square feet (ft²)",
              "in²": "Square inches (in²)",
              "L": "Liters (L)",
              "mL": "Milliliters (mL)",
              "m³": "Cubic meters (m³)",
              "US fl oz": "US fluid ounces",
              "m/s": "Meters per second (m/s)",
              "km/h": "Kilometers per hour (km/h)",
              "mph": "Miles per hour (mph)",
              "knot": "Knots",
              "kB": "Kilobytes (kB, 1,000 bytes)",
              "MB": "Megabytes (MB, 1,000,000 bytes)",
              "GB": "Gigabytes (GB, decimal)",
              "TB": "Terabytes (TB, decimal)",
              "KiB": "Kibibytes (KiB, 1,024 bytes)",
              "MiB": "Mebibytes (MiB, 1,048,576 bytes)",
              "GiB": "Gibibytes (GiB, binary)",
              "TiB": "Tebibytes (TiB, binary)",
              "Pa": "Pascals (Pa)",
              "kPa": "Kilopascals (kPa)",
              "atm": "Standard atmospheres (atm)",
              "psi": "Pounds per square inch (psi)",
              "J": "Joules (J)",
              "kJ": "Kilojoules (kJ)",
              "cal": "Thermochemical calories (cal)",
              "kcal": "Kilocalories (kcal)",
              "Wh": "Watt-hours (Wh)",
              "kWh": "Kilowatt-hours (kWh)",
              "W": "Watts (W)",
              "kW": "Kilowatts (kW)",
              "MW": "Megawatts (MW)",
              "hp": "Mechanical horsepower (hp)"
            }
          },
          {
            "key": "to",
            "label": "To",
            "value": "kPa",
            "type": "select",
            "values": [
              "Pa",
              "kPa",
              "bar",
              "atm",
              "psi"
            ],
            "labels": {
              "m": "Meters (m)",
              "km": "Kilometers (km)",
              "cm": "Centimeters (cm)",
              "mm": "Millimeters (mm)",
              "in": "Inches (in)",
              "ft": "Feet (ft)",
              "yd": "Yards (yd)",
              "mi": "Miles (mi)",
              "kg": "Kilograms (kg)",
              "g": "Grams (g)",
              "mg": "Milligrams (mg)",
              "lb": "Pounds (lb)",
              "oz": "Ounces (oz)",
              "tonne": "Metric tonnes",
              "m²": "Square meters (m²)",
              "km²": "Square kilometers (km²)",
              "cm²": "Square centimeters (cm²)",
              "ft²": "Square feet (ft²)",
              "in²": "Square inches (in²)",
              "L": "Liters (L)",
              "mL": "Milliliters (mL)",
              "m³": "Cubic meters (m³)",
              "US fl oz": "US fluid ounces",
              "m/s": "Meters per second (m/s)",
              "km/h": "Kilometers per hour (km/h)",
              "mph": "Miles per hour (mph)",
              "knot": "Knots",
              "kB": "Kilobytes (kB, 1,000 bytes)",
              "MB": "Megabytes (MB, 1,000,000 bytes)",
              "GB": "Gigabytes (GB, decimal)",
              "TB": "Terabytes (TB, decimal)",
              "KiB": "Kibibytes (KiB, 1,024 bytes)",
              "MiB": "Mebibytes (MiB, 1,048,576 bytes)",
              "GiB": "Gibibytes (GiB, binary)",
              "TiB": "Tebibytes (TiB, binary)",
              "Pa": "Pascals (Pa)",
              "kPa": "Kilopascals (kPa)",
              "atm": "Standard atmospheres (atm)",
              "psi": "Pounds per square inch (psi)",
              "J": "Joules (J)",
              "kJ": "Kilojoules (kJ)",
              "cal": "Thermochemical calories (cal)",
              "kcal": "Kilocalories (kcal)",
              "Wh": "Watt-hours (Wh)",
              "kWh": "Kilowatt-hours (kWh)",
              "W": "Watts (W)",
              "kW": "Kilowatts (kW)",
              "MW": "Megawatts (MW)",
              "hp": "Mechanical horsepower (hp)"
            }
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/pressure/run",
      "api": {
        "id": "pressure",
        "name": "Pressure",
        "category": "unit-converters",
        "description": "Convert between pascals, kilopascals, bar, atmospheres, and psi.",
        "notes": "",
        "human_path": "/en/unit-converters/pressure/",
        "method": "POST",
        "endpoint": "/api/v1/tools/pressure/run",
        "schema_url": "/api/v1/tools/pressure",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "value": {
                  "type": "number",
                  "description": "Value",
                  "default": 1.0
                },
                "from": {
                  "type": "string",
                  "description": "From",
                  "default": "Pa",
                  "enum": [
                    "Pa",
                    "kPa",
                    "bar",
                    "atm",
                    "psi"
                  ]
                },
                "to": {
                  "type": "string",
                  "description": "To",
                  "default": "kPa",
                  "enum": [
                    "Pa",
                    "kPa",
                    "bar",
                    "atm",
                    "psi"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/unit-converters/pressure/",
      "agent_url": "https://happytails.ai/agents/en/unit-converters/pressure/"
    },
    {
      "id": "speed",
      "category": "unit-converters",
      "built": true,
      "requirements": "Speed units and selected precision; separate speed from pace unless explicitly supported.",
      "implementation": {
        "fields": [
          {
            "key": "value",
            "label": "Value",
            "value": 1,
            "type": "number"
          },
          {
            "key": "from",
            "label": "From",
            "value": "m/s",
            "type": "select",
            "values": [
              "m/s",
              "km/h",
              "mph",
              "knot"
            ],
            "labels": {
              "m": "Meters (m)",
              "km": "Kilometers (km)",
              "cm": "Centimeters (cm)",
              "mm": "Millimeters (mm)",
              "in": "Inches (in)",
              "ft": "Feet (ft)",
              "yd": "Yards (yd)",
              "mi": "Miles (mi)",
              "kg": "Kilograms (kg)",
              "g": "Grams (g)",
              "mg": "Milligrams (mg)",
              "lb": "Pounds (lb)",
              "oz": "Ounces (oz)",
              "tonne": "Metric tonnes",
              "m²": "Square meters (m²)",
              "km²": "Square kilometers (km²)",
              "cm²": "Square centimeters (cm²)",
              "ft²": "Square feet (ft²)",
              "in²": "Square inches (in²)",
              "L": "Liters (L)",
              "mL": "Milliliters (mL)",
              "m³": "Cubic meters (m³)",
              "US fl oz": "US fluid ounces",
              "m/s": "Meters per second (m/s)",
              "km/h": "Kilometers per hour (km/h)",
              "mph": "Miles per hour (mph)",
              "knot": "Knots",
              "kB": "Kilobytes (kB, 1,000 bytes)",
              "MB": "Megabytes (MB, 1,000,000 bytes)",
              "GB": "Gigabytes (GB, decimal)",
              "TB": "Terabytes (TB, decimal)",
              "KiB": "Kibibytes (KiB, 1,024 bytes)",
              "MiB": "Mebibytes (MiB, 1,048,576 bytes)",
              "GiB": "Gibibytes (GiB, binary)",
              "TiB": "Tebibytes (TiB, binary)",
              "Pa": "Pascals (Pa)",
              "kPa": "Kilopascals (kPa)",
              "atm": "Standard atmospheres (atm)",
              "psi": "Pounds per square inch (psi)",
              "J": "Joules (J)",
              "kJ": "Kilojoules (kJ)",
              "cal": "Thermochemical calories (cal)",
              "kcal": "Kilocalories (kcal)",
              "Wh": "Watt-hours (Wh)",
              "kWh": "Kilowatt-hours (kWh)",
              "W": "Watts (W)",
              "kW": "Kilowatts (kW)",
              "MW": "Megawatts (MW)",
              "hp": "Mechanical horsepower (hp)"
            }
          },
          {
            "key": "to",
            "label": "To",
            "value": "km/h",
            "type": "select",
            "values": [
              "m/s",
              "km/h",
              "mph",
              "knot"
            ],
            "labels": {
              "m": "Meters (m)",
              "km": "Kilometers (km)",
              "cm": "Centimeters (cm)",
              "mm": "Millimeters (mm)",
              "in": "Inches (in)",
              "ft": "Feet (ft)",
              "yd": "Yards (yd)",
              "mi": "Miles (mi)",
              "kg": "Kilograms (kg)",
              "g": "Grams (g)",
              "mg": "Milligrams (mg)",
              "lb": "Pounds (lb)",
              "oz": "Ounces (oz)",
              "tonne": "Metric tonnes",
              "m²": "Square meters (m²)",
              "km²": "Square kilometers (km²)",
              "cm²": "Square centimeters (cm²)",
              "ft²": "Square feet (ft²)",
              "in²": "Square inches (in²)",
              "L": "Liters (L)",
              "mL": "Milliliters (mL)",
              "m³": "Cubic meters (m³)",
              "US fl oz": "US fluid ounces",
              "m/s": "Meters per second (m/s)",
              "km/h": "Kilometers per hour (km/h)",
              "mph": "Miles per hour (mph)",
              "knot": "Knots",
              "kB": "Kilobytes (kB, 1,000 bytes)",
              "MB": "Megabytes (MB, 1,000,000 bytes)",
              "GB": "Gigabytes (GB, decimal)",
              "TB": "Terabytes (TB, decimal)",
              "KiB": "Kibibytes (KiB, 1,024 bytes)",
              "MiB": "Mebibytes (MiB, 1,048,576 bytes)",
              "GiB": "Gibibytes (GiB, binary)",
              "TiB": "Tebibytes (TiB, binary)",
              "Pa": "Pascals (Pa)",
              "kPa": "Kilopascals (kPa)",
              "atm": "Standard atmospheres (atm)",
              "psi": "Pounds per square inch (psi)",
              "J": "Joules (J)",
              "kJ": "Kilojoules (kJ)",
              "cal": "Thermochemical calories (cal)",
              "kcal": "Kilocalories (kcal)",
              "Wh": "Watt-hours (Wh)",
              "kWh": "Kilowatt-hours (kWh)",
              "W": "Watts (W)",
              "kW": "Kilowatts (kW)",
              "MW": "Megawatts (MW)",
              "hp": "Mechanical horsepower (hp)"
            }
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/speed/run",
      "api": {
        "id": "speed",
        "name": "Speed",
        "category": "unit-converters",
        "description": "Convert between meters per second, kilometers per hour, miles per hour, and knots.",
        "notes": "",
        "human_path": "/en/unit-converters/speed/",
        "method": "POST",
        "endpoint": "/api/v1/tools/speed/run",
        "schema_url": "/api/v1/tools/speed",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "value": {
                  "type": "number",
                  "description": "Value",
                  "default": 1.0
                },
                "from": {
                  "type": "string",
                  "description": "From",
                  "default": "m/s",
                  "enum": [
                    "m/s",
                    "km/h",
                    "mph",
                    "knot"
                  ]
                },
                "to": {
                  "type": "string",
                  "description": "To",
                  "default": "km/h",
                  "enum": [
                    "m/s",
                    "km/h",
                    "mph",
                    "knot"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/unit-converters/speed/",
      "agent_url": "https://happytails.ai/agents/en/unit-converters/speed/"
    },
    {
      "id": "temperature",
      "category": "unit-converters",
      "built": true,
      "requirements": "Celsius/Fahrenheit/Kelvin with formulas; avoid treating temperature differences like absolute values.",
      "implementation": {
        "fields": [
          {
            "key": "value",
            "label": "Temperature",
            "value": 20,
            "type": "number"
          },
          {
            "key": "from",
            "label": "From",
            "value": "Celsius",
            "type": "select",
            "values": [
              "Celsius",
              "Fahrenheit",
              "Kelvin"
            ]
          },
          {
            "key": "to",
            "label": "To",
            "value": "Fahrenheit",
            "type": "select",
            "values": [
              "Celsius",
              "Fahrenheit",
              "Kelvin"
            ]
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/temperature/run",
      "api": {
        "id": "temperature",
        "name": "Temperature",
        "category": "unit-converters",
        "description": "Convert between Celsius, Fahrenheit, and Kelvin.",
        "notes": "",
        "human_path": "/en/unit-converters/temperature/",
        "method": "POST",
        "endpoint": "/api/v1/tools/temperature/run",
        "schema_url": "/api/v1/tools/temperature",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "value": {
                  "type": "number",
                  "description": "Temperature",
                  "default": 20.0
                },
                "from": {
                  "type": "string",
                  "description": "From",
                  "default": "Celsius",
                  "enum": [
                    "Celsius",
                    "Fahrenheit",
                    "Kelvin"
                  ]
                },
                "to": {
                  "type": "string",
                  "description": "To",
                  "default": "Fahrenheit",
                  "enum": [
                    "Celsius",
                    "Fahrenheit",
                    "Kelvin"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/unit-converters/temperature/",
      "agent_url": "https://happytails.ai/agents/en/unit-converters/temperature/"
    },
    {
      "id": "time-units",
      "category": "unit-converters",
      "built": true,
      "requirements": "Seconds/minutes/hours/days; exclude calendar months from fixed-duration assumptions.",
      "implementation": {
        "fields": [
          {
            "key": "value",
            "label": "Value",
            "value": 1,
            "type": "number"
          },
          {
            "key": "from",
            "label": "From",
            "value": "second",
            "type": "select",
            "values": [
              "second",
              "millisecond",
              "minute",
              "hour",
              "day",
              "week"
            ],
            "labels": {
              "m": "Meters (m)",
              "km": "Kilometers (km)",
              "cm": "Centimeters (cm)",
              "mm": "Millimeters (mm)",
              "in": "Inches (in)",
              "ft": "Feet (ft)",
              "yd": "Yards (yd)",
              "mi": "Miles (mi)",
              "kg": "Kilograms (kg)",
              "g": "Grams (g)",
              "mg": "Milligrams (mg)",
              "lb": "Pounds (lb)",
              "oz": "Ounces (oz)",
              "tonne": "Metric tonnes",
              "m²": "Square meters (m²)",
              "km²": "Square kilometers (km²)",
              "cm²": "Square centimeters (cm²)",
              "ft²": "Square feet (ft²)",
              "in²": "Square inches (in²)",
              "L": "Liters (L)",
              "mL": "Milliliters (mL)",
              "m³": "Cubic meters (m³)",
              "US fl oz": "US fluid ounces",
              "m/s": "Meters per second (m/s)",
              "km/h": "Kilometers per hour (km/h)",
              "mph": "Miles per hour (mph)",
              "knot": "Knots",
              "kB": "Kilobytes (kB, 1,000 bytes)",
              "MB": "Megabytes (MB, 1,000,000 bytes)",
              "GB": "Gigabytes (GB, decimal)",
              "TB": "Terabytes (TB, decimal)",
              "KiB": "Kibibytes (KiB, 1,024 bytes)",
              "MiB": "Mebibytes (MiB, 1,048,576 bytes)",
              "GiB": "Gibibytes (GiB, binary)",
              "TiB": "Tebibytes (TiB, binary)",
              "Pa": "Pascals (Pa)",
              "kPa": "Kilopascals (kPa)",
              "atm": "Standard atmospheres (atm)",
              "psi": "Pounds per square inch (psi)",
              "J": "Joules (J)",
              "kJ": "Kilojoules (kJ)",
              "cal": "Thermochemical calories (cal)",
              "kcal": "Kilocalories (kcal)",
              "Wh": "Watt-hours (Wh)",
              "kWh": "Kilowatt-hours (kWh)",
              "W": "Watts (W)",
              "kW": "Kilowatts (kW)",
              "MW": "Megawatts (MW)",
              "hp": "Mechanical horsepower (hp)"
            }
          },
          {
            "key": "to",
            "label": "To",
            "value": "millisecond",
            "type": "select",
            "values": [
              "second",
              "millisecond",
              "minute",
              "hour",
              "day",
              "week"
            ],
            "labels": {
              "m": "Meters (m)",
              "km": "Kilometers (km)",
              "cm": "Centimeters (cm)",
              "mm": "Millimeters (mm)",
              "in": "Inches (in)",
              "ft": "Feet (ft)",
              "yd": "Yards (yd)",
              "mi": "Miles (mi)",
              "kg": "Kilograms (kg)",
              "g": "Grams (g)",
              "mg": "Milligrams (mg)",
              "lb": "Pounds (lb)",
              "oz": "Ounces (oz)",
              "tonne": "Metric tonnes",
              "m²": "Square meters (m²)",
              "km²": "Square kilometers (km²)",
              "cm²": "Square centimeters (cm²)",
              "ft²": "Square feet (ft²)",
              "in²": "Square inches (in²)",
              "L": "Liters (L)",
              "mL": "Milliliters (mL)",
              "m³": "Cubic meters (m³)",
              "US fl oz": "US fluid ounces",
              "m/s": "Meters per second (m/s)",
              "km/h": "Kilometers per hour (km/h)",
              "mph": "Miles per hour (mph)",
              "knot": "Knots",
              "kB": "Kilobytes (kB, 1,000 bytes)",
              "MB": "Megabytes (MB, 1,000,000 bytes)",
              "GB": "Gigabytes (GB, decimal)",
              "TB": "Terabytes (TB, decimal)",
              "KiB": "Kibibytes (KiB, 1,024 bytes)",
              "MiB": "Mebibytes (MiB, 1,048,576 bytes)",
              "GiB": "Gibibytes (GiB, binary)",
              "TiB": "Tebibytes (TiB, binary)",
              "Pa": "Pascals (Pa)",
              "kPa": "Kilopascals (kPa)",
              "atm": "Standard atmospheres (atm)",
              "psi": "Pounds per square inch (psi)",
              "J": "Joules (J)",
              "kJ": "Kilojoules (kJ)",
              "cal": "Thermochemical calories (cal)",
              "kcal": "Kilocalories (kcal)",
              "Wh": "Watt-hours (Wh)",
              "kWh": "Kilowatt-hours (kWh)",
              "W": "Watts (W)",
              "kW": "Kilowatts (kW)",
              "MW": "Megawatts (MW)",
              "hp": "Mechanical horsepower (hp)"
            }
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/time-units/run",
      "api": {
        "id": "time-units",
        "name": "Time units",
        "category": "unit-converters",
        "description": "Convert between milliseconds, seconds, minutes, hours, days, and weeks.",
        "notes": "",
        "human_path": "/en/unit-converters/time-units/",
        "method": "POST",
        "endpoint": "/api/v1/tools/time-units/run",
        "schema_url": "/api/v1/tools/time-units",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "value": {
                  "type": "number",
                  "description": "Value",
                  "default": 1.0
                },
                "from": {
                  "type": "string",
                  "description": "From",
                  "default": "second",
                  "enum": [
                    "second",
                    "millisecond",
                    "minute",
                    "hour",
                    "day",
                    "week"
                  ]
                },
                "to": {
                  "type": "string",
                  "description": "To",
                  "default": "millisecond",
                  "enum": [
                    "second",
                    "millisecond",
                    "minute",
                    "hour",
                    "day",
                    "week"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/unit-converters/time-units/",
      "agent_url": "https://happytails.ai/agents/en/unit-converters/time-units/"
    },
    {
      "id": "volume",
      "category": "unit-converters",
      "built": true,
      "requirements": "Distinguish US/Imperial gallons and cups; disclose context and precision.",
      "implementation": {
        "fields": [
          {
            "key": "value",
            "label": "Value",
            "value": 1,
            "type": "number"
          },
          {
            "key": "from",
            "label": "From",
            "value": "L",
            "type": "select",
            "values": [
              "L",
              "mL",
              "m³",
              "US gallon",
              "Imperial gallon",
              "US fl oz"
            ],
            "labels": {
              "m": "Meters (m)",
              "km": "Kilometers (km)",
              "cm": "Centimeters (cm)",
              "mm": "Millimeters (mm)",
              "in": "Inches (in)",
              "ft": "Feet (ft)",
              "yd": "Yards (yd)",
              "mi": "Miles (mi)",
              "kg": "Kilograms (kg)",
              "g": "Grams (g)",
              "mg": "Milligrams (mg)",
              "lb": "Pounds (lb)",
              "oz": "Ounces (oz)",
              "tonne": "Metric tonnes",
              "m²": "Square meters (m²)",
              "km²": "Square kilometers (km²)",
              "cm²": "Square centimeters (cm²)",
              "ft²": "Square feet (ft²)",
              "in²": "Square inches (in²)",
              "L": "Liters (L)",
              "mL": "Milliliters (mL)",
              "m³": "Cubic meters (m³)",
              "US fl oz": "US fluid ounces",
              "m/s": "Meters per second (m/s)",
              "km/h": "Kilometers per hour (km/h)",
              "mph": "Miles per hour (mph)",
              "knot": "Knots",
              "kB": "Kilobytes (kB, 1,000 bytes)",
              "MB": "Megabytes (MB, 1,000,000 bytes)",
              "GB": "Gigabytes (GB, decimal)",
              "TB": "Terabytes (TB, decimal)",
              "KiB": "Kibibytes (KiB, 1,024 bytes)",
              "MiB": "Mebibytes (MiB, 1,048,576 bytes)",
              "GiB": "Gibibytes (GiB, binary)",
              "TiB": "Tebibytes (TiB, binary)",
              "Pa": "Pascals (Pa)",
              "kPa": "Kilopascals (kPa)",
              "atm": "Standard atmospheres (atm)",
              "psi": "Pounds per square inch (psi)",
              "J": "Joules (J)",
              "kJ": "Kilojoules (kJ)",
              "cal": "Thermochemical calories (cal)",
              "kcal": "Kilocalories (kcal)",
              "Wh": "Watt-hours (Wh)",
              "kWh": "Kilowatt-hours (kWh)",
              "W": "Watts (W)",
              "kW": "Kilowatts (kW)",
              "MW": "Megawatts (MW)",
              "hp": "Mechanical horsepower (hp)"
            }
          },
          {
            "key": "to",
            "label": "To",
            "value": "mL",
            "type": "select",
            "values": [
              "L",
              "mL",
              "m³",
              "US gallon",
              "Imperial gallon",
              "US fl oz"
            ],
            "labels": {
              "m": "Meters (m)",
              "km": "Kilometers (km)",
              "cm": "Centimeters (cm)",
              "mm": "Millimeters (mm)",
              "in": "Inches (in)",
              "ft": "Feet (ft)",
              "yd": "Yards (yd)",
              "mi": "Miles (mi)",
              "kg": "Kilograms (kg)",
              "g": "Grams (g)",
              "mg": "Milligrams (mg)",
              "lb": "Pounds (lb)",
              "oz": "Ounces (oz)",
              "tonne": "Metric tonnes",
              "m²": "Square meters (m²)",
              "km²": "Square kilometers (km²)",
              "cm²": "Square centimeters (cm²)",
              "ft²": "Square feet (ft²)",
              "in²": "Square inches (in²)",
              "L": "Liters (L)",
              "mL": "Milliliters (mL)",
              "m³": "Cubic meters (m³)",
              "US fl oz": "US fluid ounces",
              "m/s": "Meters per second (m/s)",
              "km/h": "Kilometers per hour (km/h)",
              "mph": "Miles per hour (mph)",
              "knot": "Knots",
              "kB": "Kilobytes (kB, 1,000 bytes)",
              "MB": "Megabytes (MB, 1,000,000 bytes)",
              "GB": "Gigabytes (GB, decimal)",
              "TB": "Terabytes (TB, decimal)",
              "KiB": "Kibibytes (KiB, 1,024 bytes)",
              "MiB": "Mebibytes (MiB, 1,048,576 bytes)",
              "GiB": "Gibibytes (GiB, binary)",
              "TiB": "Tebibytes (TiB, binary)",
              "Pa": "Pascals (Pa)",
              "kPa": "Kilopascals (kPa)",
              "atm": "Standard atmospheres (atm)",
              "psi": "Pounds per square inch (psi)",
              "J": "Joules (J)",
              "kJ": "Kilojoules (kJ)",
              "cal": "Thermochemical calories (cal)",
              "kcal": "Kilocalories (kcal)",
              "Wh": "Watt-hours (Wh)",
              "kWh": "Kilowatt-hours (kWh)",
              "W": "Watts (W)",
              "kW": "Kilowatts (kW)",
              "MW": "Megawatts (MW)",
              "hp": "Mechanical horsepower (hp)"
            }
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/volume/run",
      "api": {
        "id": "volume",
        "name": "Volume",
        "category": "unit-converters",
        "description": "Convert between liters, milliliters, and US or Imperial volume units.",
        "notes": "",
        "human_path": "/en/unit-converters/volume/",
        "method": "POST",
        "endpoint": "/api/v1/tools/volume/run",
        "schema_url": "/api/v1/tools/volume",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "value": {
                  "type": "number",
                  "description": "Value",
                  "default": 1.0
                },
                "from": {
                  "type": "string",
                  "description": "From",
                  "default": "L",
                  "enum": [
                    "L",
                    "mL",
                    "m³",
                    "US gallon",
                    "Imperial gallon",
                    "US fl oz"
                  ]
                },
                "to": {
                  "type": "string",
                  "description": "To",
                  "default": "mL",
                  "enum": [
                    "L",
                    "mL",
                    "m³",
                    "US gallon",
                    "Imperial gallon",
                    "US fl oz"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/unit-converters/volume/",
      "agent_url": "https://happytails.ai/agents/en/unit-converters/volume/"
    },
    {
      "id": "weight",
      "category": "unit-converters",
      "built": true,
      "requirements": "Mass units, precision and clear mass/force distinction; link to kg-to-lb task.",
      "implementation": {
        "fields": [
          {
            "key": "value",
            "label": "Value",
            "value": 1,
            "type": "number"
          },
          {
            "key": "from",
            "label": "From",
            "value": "kg",
            "type": "select",
            "values": [
              "kg",
              "g",
              "mg",
              "lb",
              "oz",
              "tonne"
            ],
            "labels": {
              "m": "Meters (m)",
              "km": "Kilometers (km)",
              "cm": "Centimeters (cm)",
              "mm": "Millimeters (mm)",
              "in": "Inches (in)",
              "ft": "Feet (ft)",
              "yd": "Yards (yd)",
              "mi": "Miles (mi)",
              "kg": "Kilograms (kg)",
              "g": "Grams (g)",
              "mg": "Milligrams (mg)",
              "lb": "Pounds (lb)",
              "oz": "Ounces (oz)",
              "tonne": "Metric tonnes",
              "m²": "Square meters (m²)",
              "km²": "Square kilometers (km²)",
              "cm²": "Square centimeters (cm²)",
              "ft²": "Square feet (ft²)",
              "in²": "Square inches (in²)",
              "L": "Liters (L)",
              "mL": "Milliliters (mL)",
              "m³": "Cubic meters (m³)",
              "US fl oz": "US fluid ounces",
              "m/s": "Meters per second (m/s)",
              "km/h": "Kilometers per hour (km/h)",
              "mph": "Miles per hour (mph)",
              "knot": "Knots",
              "kB": "Kilobytes (kB, 1,000 bytes)",
              "MB": "Megabytes (MB, 1,000,000 bytes)",
              "GB": "Gigabytes (GB, decimal)",
              "TB": "Terabytes (TB, decimal)",
              "KiB": "Kibibytes (KiB, 1,024 bytes)",
              "MiB": "Mebibytes (MiB, 1,048,576 bytes)",
              "GiB": "Gibibytes (GiB, binary)",
              "TiB": "Tebibytes (TiB, binary)",
              "Pa": "Pascals (Pa)",
              "kPa": "Kilopascals (kPa)",
              "atm": "Standard atmospheres (atm)",
              "psi": "Pounds per square inch (psi)",
              "J": "Joules (J)",
              "kJ": "Kilojoules (kJ)",
              "cal": "Thermochemical calories (cal)",
              "kcal": "Kilocalories (kcal)",
              "Wh": "Watt-hours (Wh)",
              "kWh": "Kilowatt-hours (kWh)",
              "W": "Watts (W)",
              "kW": "Kilowatts (kW)",
              "MW": "Megawatts (MW)",
              "hp": "Mechanical horsepower (hp)"
            }
          },
          {
            "key": "to",
            "label": "To",
            "value": "g",
            "type": "select",
            "values": [
              "kg",
              "g",
              "mg",
              "lb",
              "oz",
              "tonne"
            ],
            "labels": {
              "m": "Meters (m)",
              "km": "Kilometers (km)",
              "cm": "Centimeters (cm)",
              "mm": "Millimeters (mm)",
              "in": "Inches (in)",
              "ft": "Feet (ft)",
              "yd": "Yards (yd)",
              "mi": "Miles (mi)",
              "kg": "Kilograms (kg)",
              "g": "Grams (g)",
              "mg": "Milligrams (mg)",
              "lb": "Pounds (lb)",
              "oz": "Ounces (oz)",
              "tonne": "Metric tonnes",
              "m²": "Square meters (m²)",
              "km²": "Square kilometers (km²)",
              "cm²": "Square centimeters (cm²)",
              "ft²": "Square feet (ft²)",
              "in²": "Square inches (in²)",
              "L": "Liters (L)",
              "mL": "Milliliters (mL)",
              "m³": "Cubic meters (m³)",
              "US fl oz": "US fluid ounces",
              "m/s": "Meters per second (m/s)",
              "km/h": "Kilometers per hour (km/h)",
              "mph": "Miles per hour (mph)",
              "knot": "Knots",
              "kB": "Kilobytes (kB, 1,000 bytes)",
              "MB": "Megabytes (MB, 1,000,000 bytes)",
              "GB": "Gigabytes (GB, decimal)",
              "TB": "Terabytes (TB, decimal)",
              "KiB": "Kibibytes (KiB, 1,024 bytes)",
              "MiB": "Mebibytes (MiB, 1,048,576 bytes)",
              "GiB": "Gibibytes (GiB, binary)",
              "TiB": "Tebibytes (TiB, binary)",
              "Pa": "Pascals (Pa)",
              "kPa": "Kilopascals (kPa)",
              "atm": "Standard atmospheres (atm)",
              "psi": "Pounds per square inch (psi)",
              "J": "Joules (J)",
              "kJ": "Kilojoules (kJ)",
              "cal": "Thermochemical calories (cal)",
              "kcal": "Kilocalories (kcal)",
              "Wh": "Watt-hours (Wh)",
              "kWh": "Kilowatt-hours (kWh)",
              "W": "Watts (W)",
              "kW": "Kilowatts (kW)",
              "MW": "Megawatts (MW)",
              "hp": "Mechanical horsepower (hp)"
            }
          }
        ],
        "input": false,
        "note": "",
        "live": true,
        "presentation": "metrics",
        "experience": {
          "automatic": true,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Change the input or settings to update your result. Results update as you type. Up to 1,000,000 characters.",
          "action": null
        },
        "mode": "automatic",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/weight/run",
      "api": {
        "id": "weight",
        "name": "Weight",
        "category": "unit-converters",
        "description": "Convert between kilograms, pounds, ounces, and other mass units.",
        "notes": "",
        "human_path": "/en/unit-converters/weight/",
        "method": "POST",
        "endpoint": "/api/v1/tools/weight/run",
        "schema_url": "/api/v1/tools/weight",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "value": {
                  "type": "number",
                  "description": "Value",
                  "default": 1.0
                },
                "from": {
                  "type": "string",
                  "description": "From",
                  "default": "kg",
                  "enum": [
                    "kg",
                    "g",
                    "mg",
                    "lb",
                    "oz",
                    "tonne"
                  ]
                },
                "to": {
                  "type": "string",
                  "description": "To",
                  "default": "g",
                  "enum": [
                    "kg",
                    "g",
                    "mg",
                    "lb",
                    "oz",
                    "tonne"
                  ]
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/unit-converters/weight/",
      "agent_url": "https://happytails.ai/agents/en/unit-converters/weight/"
    },
    {
      "id": "hreflang-generator",
      "category": "web-tools",
      "built": true,
      "requirements": "Language-region validation, reciprocal alternate sets and x-default; export annotations.",
      "implementation": {
        "fields": [],
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/hreflang-generator/run",
      "api": {
        "id": "hreflang-generator",
        "name": "Hreflang generator",
        "category": "web-tools",
        "description": "Language-region validation, reciprocal alternate sets and x-default.",
        "notes": "",
        "human_path": "/en/web-tools/hreflang-generator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/hreflang-generator/run",
        "schema_url": "/api/v1/tools/hreflang-generator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/web-tools/hreflang-generator/",
      "agent_url": "https://happytails.ai/agents/en/web-tools/hreflang-generator/"
    },
    {
      "id": "http-status-checker",
      "category": "web-tools",
      "built": true,
      "requirements": "Redirect chain, status, selected headers and fetch timestamp; public HTTP endpoints only.",
      "implementation": {
        "fields": [],
        "processing": "Server required",
        "note": "Uses the local diagnostic server to contact the supplied public host or DNS/RDAP provider. Only public internet addresses are permitted; requests time out and redirects are bounded.",
        "experience": {
          "automatic": false,
          "single": true,
          "label": "Website URL",
          "placeholder": "https://happytails.ai",
          "help": "Enter one complete HTTP or HTTPS URL. Only public addresses and ports 80 or 443 are supported.",
          "action": "Check URL"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/http-status-checker/run",
      "api": {
        "id": "http-status-checker",
        "name": "HTTP status checker",
        "category": "web-tools",
        "description": "Redirect chain, status, selected headers and fetch timestamp.",
        "notes": "Uses the local diagnostic server to contact the supplied public host or DNS/RDAP provider. Only public internet addresses are permitted; requests time out and redirects are bounded.",
        "human_path": "/en/web-tools/http-status-checker/",
        "method": "POST",
        "endpoint": "/api/v1/tools/http-status-checker/run",
        "schema_url": "/api/v1/tools/http-status-checker",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; contacts public network services",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": null
        }
      },
      "agent_processing": "Server; contacts public network services",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/web-tools/http-status-checker/",
      "agent_url": "https://happytails.ai/agents/en/web-tools/http-status-checker/"
    },
    {
      "id": "meta-tag-generator",
      "category": "web-tools",
      "built": true,
      "requirements": "Escaped title, description, robots and social metadata; live snippet is approximate.",
      "implementation": {
        "fields": [
          {
            "key": "title",
            "label": "Page title",
            "value": "",
            "type": "text"
          },
          {
            "key": "description",
            "label": "Description",
            "value": "",
            "type": "text"
          },
          {
            "key": "index",
            "label": "Allow indexing",
            "value": true,
            "type": "checkbox"
          }
        ],
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/meta-tag-generator/run",
      "api": {
        "id": "meta-tag-generator",
        "name": "Meta tag generator",
        "category": "web-tools",
        "description": "Escaped title, description, robots and social metadata.",
        "notes": "",
        "human_path": "/en/web-tools/meta-tag-generator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/meta-tag-generator/run",
        "schema_url": "/api/v1/tools/meta-tag-generator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "title": {
                  "type": "string",
                  "description": "Page title",
                  "default": ""
                },
                "description": {
                  "type": "string",
                  "description": "Description",
                  "default": ""
                },
                "index": {
                  "type": "boolean",
                  "description": "Allow indexing",
                  "default": true
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/web-tools/meta-tag-generator/",
      "agent_url": "https://happytails.ai/agents/en/web-tools/meta-tag-generator/"
    },
    {
      "id": "redirect-checker",
      "category": "web-tools",
      "built": true,
      "requirements": "Full chain including loops and relative locations; distinguish HTTP from script redirects.",
      "implementation": {
        "fields": [],
        "processing": "Server required",
        "note": "Uses the local diagnostic server to contact the supplied public host or DNS/RDAP provider. Only public internet addresses are permitted; requests time out and redirects are bounded.",
        "experience": {
          "automatic": false,
          "single": true,
          "label": "Website URL",
          "placeholder": "https://happytails.ai",
          "help": "Enter one complete HTTP or HTTPS URL. Only public addresses and ports 80 or 443 are supported.",
          "action": "Check URL"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/redirect-checker/run",
      "api": {
        "id": "redirect-checker",
        "name": "Redirect checker",
        "category": "web-tools",
        "description": "Full chain including loops and relative locations.",
        "notes": "Uses the local diagnostic server to contact the supplied public host or DNS/RDAP provider. Only public internet addresses are permitted; requests time out and redirects are bounded.",
        "human_path": "/en/web-tools/redirect-checker/",
        "method": "POST",
        "endpoint": "/api/v1/tools/redirect-checker/run",
        "schema_url": "/api/v1/tools/redirect-checker",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; contacts public network services",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": null
        }
      },
      "agent_processing": "Server; contacts public network services",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/web-tools/redirect-checker/",
      "agent_url": "https://happytails.ai/agents/en/web-tools/redirect-checker/"
    },
    {
      "id": "robots-txt-tester",
      "category": "web-tools",
      "built": true,
      "requirements": "Paste-first rules evaluation by user-agent and URL; show winning rule.",
      "implementation": {
        "fields": [
          {
            "key": "url",
            "label": "URL to test",
            "value": "https://happytails.ai/path",
            "type": "text"
          },
          {
            "key": "agent",
            "label": "Crawler user agent",
            "value": "Googlebot",
            "type": "text"
          }
        ],
        "note": "Paste robots.txt content; this tool does not fetch or change the remote file.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/robots-txt-tester/run",
      "api": {
        "id": "robots-txt-tester",
        "name": "Robots txt tester",
        "category": "web-tools",
        "description": "Check whether robots.txt rules allow a crawler to visit a URL.",
        "notes": "Paste robots.txt content; this tool does not fetch or change the remote file.",
        "human_path": "/en/web-tools/robots-txt-tester/",
        "method": "POST",
        "endpoint": "/api/v1/tools/robots-txt-tester/run",
        "schema_url": "/api/v1/tools/robots-txt-tester",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "url": {
                  "type": "string",
                  "description": "URL to test",
                  "default": "https://happytails.ai/path"
                },
                "agent": {
                  "type": "string",
                  "description": "Crawler user agent",
                  "default": "Googlebot"
                }
              }
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/web-tools/robots-txt-tester/",
      "agent_url": "https://happytails.ai/agents/en/web-tools/robots-txt-tester/"
    },
    {
      "id": "schema-generator",
      "category": "web-tools",
      "built": true,
      "requirements": "Supported Schema.org types with validation; no promise of search features.",
      "implementation": {
        "fields": [],
        "note": "Supply Schema.org properties as JSON. This formats JSON-LD; it does not guarantee rich-result eligibility.",
        "experience": {
          "automatic": false,
          "single": false,
          "label": "Your text",
          "placeholder": "Type or paste your input…",
          "help": "Up to 1,000,000 characters. Review the settings before running.",
          "action": null
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/schema-generator/run",
      "api": {
        "id": "schema-generator",
        "name": "Schema generator",
        "category": "web-tools",
        "description": "Supported Schema.org types with validation.",
        "notes": "Supply Schema.org properties as JSON. This formats JSON-LD; it does not guarantee rich-result eligibility.",
        "human_path": "/en/web-tools/schema-generator/",
        "method": "POST",
        "endpoint": "/api/v1/tools/schema-generator/run",
        "schema_url": "/api/v1/tools/schema-generator",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; same transformation code as browser tools",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": 12
        }
      },
      "agent_processing": "Server; same transformation code as browser tools",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/web-tools/schema-generator/",
      "agent_url": "https://happytails.ai/agents/en/web-tools/schema-generator/"
    },
    {
      "id": "security-headers",
      "category": "web-tools",
      "built": true,
      "requirements": "Observed response headers with scoped explanations; no universal security score.",
      "implementation": {
        "fields": [],
        "processing": "Server required",
        "note": "Uses the local diagnostic server to contact the supplied public host or DNS/RDAP provider. Only public internet addresses are permitted; requests time out and redirects are bounded.",
        "experience": {
          "automatic": false,
          "single": true,
          "label": "Website URL",
          "placeholder": "https://happytails.ai",
          "help": "Enter one complete HTTP or HTTPS URL. Only public addresses and ports 80 or 443 are supported.",
          "action": "Check URL"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/security-headers/run",
      "api": {
        "id": "security-headers",
        "name": "Security headers",
        "category": "web-tools",
        "description": "Observed response headers with scoped explanations.",
        "notes": "Uses the local diagnostic server to contact the supplied public host or DNS/RDAP provider. Only public internet addresses are permitted; requests time out and redirects are bounded.",
        "human_path": "/en/web-tools/security-headers/",
        "method": "POST",
        "endpoint": "/api/v1/tools/security-headers/run",
        "schema_url": "/api/v1/tools/security-headers",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; contacts public network services",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": null
        }
      },
      "agent_processing": "Server; contacts public network services",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/web-tools/security-headers/",
      "agent_url": "https://happytails.ai/agents/en/web-tools/security-headers/"
    },
    {
      "id": "ssl-checker",
      "category": "web-tools",
      "built": true,
      "requirements": "Hostname match, certificate chain and expiry; indicate assessment scope and check time.",
      "implementation": {
        "fields": [],
        "processing": "Server required",
        "note": "Uses the local diagnostic server to contact the supplied public host or DNS/RDAP provider. Only public internet addresses are permitted; requests time out and redirects are bounded.",
        "experience": {
          "automatic": false,
          "single": true,
          "label": "Domain name",
          "placeholder": "happytails.ai",
          "help": "Enter one domain name without https://, a path or a port.",
          "action": "Check SSL"
        },
        "mode": "explicit",
        "interactive": false
      },
      "execution": "POST /api/v1/tools/ssl-checker/run",
      "api": {
        "id": "ssl-checker",
        "name": "SSL checker",
        "category": "web-tools",
        "description": "Hostname match, certificate chain and expiry.",
        "notes": "Uses the local diagnostic server to contact the supplied public host or DNS/RDAP provider. Only public internet addresses are permitted; requests time out and redirects are bounded.",
        "human_path": "/en/web-tools/ssl-checker/",
        "method": "POST",
        "endpoint": "/api/v1/tools/ssl-checker/run",
        "schema_url": "/api/v1/tools/ssl-checker",
        "input_schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "input": {
              "type": "string",
              "maxLength": 1000000,
              "default": "",
              "description": "Plain text input. File tools use files instead unless otherwise documented."
            },
            "options": {
              "type": "object",
              "additionalProperties": false,
              "properties": {}
            }
          }
        },
        "output_schema": {
          "type": "object",
          "required": [
            "tool",
            "result"
          ],
          "properties": {
            "tool": {
              "type": "string"
            },
            "result": {
              "type": "object",
              "required": [
                "text",
                "files"
              ],
              "properties": {
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "description": "Parsed JSON when the textual result is JSON."
                },
                "name": {
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "name",
                      "mime",
                      "bytes",
                      "base64"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "base64": {
                        "type": "string",
                        "contentEncoding": "base64"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "processing": "Server; contacts public network services",
        "limits": {
          "request_bytes": 8388608,
          "input_characters": 1000000,
          "files_bytes": 5242880,
          "max_files": 0,
          "timeout_seconds": null
        }
      },
      "agent_processing": "Server; contacts public network services",
      "browser_agent": {
        "supported": true,
        "name": "run_current_tool",
        "discovery": "WebMCP on the human page in a supporting browser",
        "verification": "See audit/API-AUDIT.md; availability is not verification"
      },
      "human_url": "https://happytails.ai/en/web-tools/ssl-checker/",
      "agent_url": "https://happytails.ai/agents/en/web-tools/ssl-checker/"
    }
  ]
}