{
  "openapi": "3.1.1",
  "info": {
    "title": "MP3 Tag & Cover Editor API",
    "version": "1.0.0",
    "summary": "Edit MP3 ID3 tags (title, artist, album, year…) and add, replace or remove the cover.",
    "description": "Every endpoint performs the same calculation as the human page and returns inputs, result, units, assumptions, sources, warnings and computedAt. MCP endpoint: /mcp."
  },
  "servers": [
    {
      "url": "https://mp3tagcovereditor.usefulweb.site"
    }
  ],
  "paths": {
    "/api/v1/calculate": {
      "post": {
        "operationId": "calculate",
        "summary": "Edit MP3 ID3 tags (title, artist, album, year…) and add, replace or remove the cover.",
        "description": "Shows the ID3 tags and album cover of an MP3, lets you edit title, artist, album, album artist, year, track, genre and comment, and adds, replaces or removes the cover image (PNG/JPG). Writes ID3v2.3 or v2.4 without re-encoding: the audio stays bit-identical, which the tool verifies.\n\nMethodology:\n- The file must be an MP3 by content (ID3 header or MPEG audio frame sync). ffprobe reads the existing tags and the attached picture.\n- ffmpeg copies the audio frames unchanged (-c copy), copies the existing tags (-map_metadata 0) and then sets each field you filled in (title, artist, album, album_artist, date, track, genre, comment). Empty fields keep their value; tags you mark for removal are cleared.\n- A new cover is checked by its content (PNG/JPG, max 5 MB) and stored as an APIC \"Cover (front)\" attached picture. Removing the cover drops the picture stream.\n- Afterwards the MD5 of the audio frames before and after is compared, and ffprobe reads the new tags back for the report.",
        "tags": [
          "media"
        ],
        "x-mcp-tool": "mp3_tag_cover_editor",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Mp3TagCoverEditorInput"
              },
              "examples": {
                "example1": {
                  "summary": "Set album and year, add a cover",
                  "value": {
                    "file": {
                      "filename": "tone.mp3",
                      "contentType": "audio/mpeg",
                      "contentBase64": "SUQzAwAAAAAANFRJVDIAAAALAAAAVGVzdCB0b25lAFRQRTEAAAALAAAAdXNlZnVsd2ViAAAAAAAAAAAAAAD/4zjAAAAAAAAAAAAASW5mbwAAAA8AAAAJAAADYABVVVVVVVVVVVVVVWpqampqampqampqgICAgICAgICAgICVlZWVlZWVlZWVlaqqqqqqqqqqqqqqwMDAwMDAwMDAwMDV1dXV1dXV1dXV1erq6urq6urq6urq//////////////8AAAAATGF2ZiBsYW1lAAAAAAAAAAAAAAAAJAJgAAAAAAAAA2DhWsr/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/4xjEAAyokqh5SAAAD22/4d3d3v/RESv5d3f5SSwbgLgLgLg3PlAxw/yhz9/R7+j38HAxkAffWBDmgH+Ud39CgQkKRFiBEz//4xjECA3w6qDBlDgA5MkBJoc7/EBhyQNsGAOBS4BzxgokpgaxKNMIQcg9HhsNv/x0ajU4GhL/hIGhKdBq////////////////4xjECw8QpjgB3gAA+GhGAAYBYAxfoGgIGBqDgYSYPhhOi9GJrekZAAshh+g1GCWCYAgOwqAOYCAAJbFkl+rfoA//b7/L5fX/4xjECQqwjo5YCbRi/n3qiICUpOT5DnL9WR4Ms63+X06P/v9H/+//+nJf+t9GXtsQBtdfrcl5/f+V1eIwQL/nESYRBr0i8sr/4xjEGQtIloJYCnZigON9/lP9n9b/T9v37q/9P2//1fRV///5O3qXQOATAhMCmwMhwSPQYQHRBgcjAEgOoWAuAIB4YAGRACL/4xjEJgpYpjQABvxEbLUb6v///jGAGAADfQMAIBwMCwEgEAvAxGjLAx9m1A6uxbA3pD+AwbAgAwDAJACBeAkAoj4ZgQohCDD/4xjENw04pkABVgAAAR/itBmDQVp/WLIJwRwGKJAwM/DsNjcZwDM5yDpBHgAgGAy0hSC/v8A3wDWMsT8L2PP//zMe5udL5uv/4xjEPRaRlozJlWgAL///+brMwdB8Bn//oB8BmiY1//9BMaaJuNf//3IVBd2AA//aqqp/9VVVOdqOJAwVLAwCARKyIBJV/QX/4xjEHQ1AmqR5xggBBn/0FCv8FBn/FBQp/xQYK/oKFHfiSf/9TEFNRTQuMSAoYWxwaGEgMClVVVVVVVVVVVVVVVVVVVVVVVU="
                    },
                    "album": "Test Signals",
                    "year": "2026",
                    "track": "1/2",
                    "coverAction": "replace",
                    "cover": {
                      "filename": "cover.png",
                      "contentType": "image/png",
                      "contentBase64": "iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAIAAABLbSncAAAACXBIWXMAAAABAAAAAQBPJcTWAAAAFElEQVR4nGMUCXjHgA2wYBUdtBIAESEBcPFXW6IAAAAASUVORK5CYII="
                    }
                  }
                },
                "example2": {
                  "summary": "Read tags only (no changes)",
                  "value": {
                    "file": {
                      "filename": "tone.mp3",
                      "contentType": "audio/mpeg",
                      "contentBase64": "SUQzAwAAAAAANFRJVDIAAAALAAAAVGVzdCB0b25lAFRQRTEAAAALAAAAdXNlZnVsd2ViAAAAAAAAAAAAAAD/4zjAAAAAAAAAAAAASW5mbwAAAA8AAAAJAAADYABVVVVVVVVVVVVVVWpqampqampqampqgICAgICAgICAgICVlZWVlZWVlZWVlaqqqqqqqqqqqqqqwMDAwMDAwMDAwMDV1dXV1dXV1dXV1erq6urq6urq6urq//////////////8AAAAATGF2ZiBsYW1lAAAAAAAAAAAAAAAAJAJgAAAAAAAAA2DhWsr/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/4xjEAAyokqh5SAAAD22/4d3d3v/RESv5d3f5SSwbgLgLgLg3PlAxw/yhz9/R7+j38HAxkAffWBDmgH+Ud39CgQkKRFiBEz//4xjECA3w6qDBlDgA5MkBJoc7/EBhyQNsGAOBS4BzxgokpgaxKNMIQcg9HhsNv/x0ajU4GhL/hIGhKdBq////////////////4xjECw8QpjgB3gAA+GhGAAYBYAxfoGgIGBqDgYSYPhhOi9GJrekZAAshh+g1GCWCYAgOwqAOYCAAJbFkl+rfoA//b7/L5fX/4xjECQqwjo5YCbRi/n3qiICUpOT5DnL9WR4Ms63+X06P/v9H/+//+nJf+t9GXtsQBtdfrcl5/f+V1eIwQL/nESYRBr0i8sr/4xjEGQtIloJYCnZigON9/lP9n9b/T9v37q/9P2//1fRV///5O3qXQOATAhMCmwMhwSPQYQHRBgcjAEgOoWAuAIB4YAGRACL/4xjEJgpYpjQABvxEbLUb6v///jGAGAADfQMAIBwMCwEgEAvAxGjLAx9m1A6uxbA3pD+AwbAgAwDAJACBeAkAoj4ZgQohCDD/4xjENw04pkABVgAAAR/itBmDQVp/WLIJwRwGKJAwM/DsNjcZwDM5yDpBHgAgGAy0hSC/v8A3wDWMsT8L2PP//zMe5udL5uv/4xjEPRaRlozJlWgAL///+brMwdB8Bn//oB8BmiY1//9BMaaJuNf//3IVBd2AA//aqqp/9VVVOdqOJAwVLAwCARKyIBJV/QX/4xjEHQ1AmqR5xggBBn/0FCv8FBn/FBQp/xQYK/oKFHfiSf/9TEFNRTQuMSAoYWxwaGEgMClVVVVVVVVVVVVVVVVVVVVVVVU="
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Mp3TagCoverEditorResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tool": {
      "get": {
        "operationId": "getToolDefinition",
        "summary": "Inputs, output schema and examples for this tool",
        "responses": {
          "200": {
            "description": "Tool definition.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "RFC 9457 problem details. 422 responses include per-field `errors`.",
        "required": [
          "type",
          "title",
          "status",
          "detail"
        ],
        "properties": {
          "type": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "field",
                "message"
              ],
              "properties": {
                "field": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "Mp3TagCoverEditorInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "file": {
            "title": "MP3 file",
            "description": "MP3 only, max 100 MB. Processed on our server in a private temporary folder that is deleted afterwards; the result can be downloaded for about 2 hours. Upload as {filename, contentType?, contentBase64}. Max 102400 KiB. Accepts .mp3,audio/mpeg.",
            "type": "object",
            "additionalProperties": false,
            "required": [
              "filename",
              "contentBase64"
            ],
            "properties": {
              "filename": {
                "type": "string"
              },
              "contentType": {
                "type": "string"
              },
              "contentBase64": {
                "type": "string"
              }
            }
          },
          "title": {
            "title": "Title",
            "description": "Empty fields keep their current value.",
            "type": "string",
            "maxLength": 120
          },
          "artist": {
            "title": "Artist",
            "type": "string",
            "maxLength": 120
          },
          "album": {
            "title": "Album",
            "type": "string",
            "maxLength": 120
          },
          "albumArtist": {
            "title": "Album artist",
            "type": "string",
            "maxLength": 120
          },
          "year": {
            "title": "Year",
            "description": "YYYY or YYYY-MM-DD. Empty = keep the current value.",
            "type": "string",
            "maxLength": 120
          },
          "track": {
            "title": "Track",
            "description": "e.g. 3 or 3/12. Empty = keep the current value.",
            "type": "string",
            "maxLength": 120
          },
          "genre": {
            "title": "Genre",
            "type": "string",
            "maxLength": 120
          },
          "comment": {
            "title": "Comment",
            "type": "string",
            "maxLength": 250
          },
          "clearTags": {
            "title": "Remove these tags",
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "title",
                "artist",
                "album",
                "albumArtist",
                "year",
                "track",
                "genre",
                "comment"
              ]
            }
          },
          "coverAction": {
            "title": "Cover image",
            "type": "string",
            "enum": [
              "keep",
              "replace",
              "remove"
            ],
            "default": "keep"
          },
          "cover": {
            "title": "New cover (PNG or JPG)",
            "description": "Max 5 MB. Square images of 500–1400 px work best in players. Upload as {filename, contentType?, contentBase64}. Max 5120 KiB. Accepts .png,.jpg,.jpeg,image/png,image/jpeg.",
            "type": "object",
            "additionalProperties": false,
            "required": [
              "filename",
              "contentBase64"
            ],
            "properties": {
              "filename": {
                "type": "string"
              },
              "contentType": {
                "type": "string"
              },
              "contentBase64": {
                "type": "string"
              }
            }
          },
          "id3Version": {
            "title": "ID3 version",
            "type": "string",
            "enum": [
              "3",
              "4"
            ],
            "default": "3"
          },
          "writeId3v1": {
            "title": "Also write an ID3v1 tag (for very old players)",
            "type": "boolean",
            "default": false
          }
        },
        "required": [
          "file"
        ]
      },
      "Mp3TagCoverEditorResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "tagsBefore",
              "tagsAfter",
              "changed",
              "coverBefore",
              "coverAfter",
              "id3Version",
              "audioUnchanged",
              "durationSeconds",
              "outputBytes",
              "artifact"
            ],
            "properties": {
              "tagsBefore": {
                "type": "object",
                "additionalProperties": {
                  "type": [
                    "string",
                    "null"
                  ]
                }
              },
              "tagsAfter": {
                "type": "object",
                "additionalProperties": {
                  "type": [
                    "string",
                    "null"
                  ]
                }
              },
              "changed": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "coverBefore": {
                "type": [
                  "object",
                  "null"
                ]
              },
              "coverAfter": {
                "type": [
                  "object",
                  "null"
                ]
              },
              "id3Version": {
                "type": "string",
                "enum": [
                  "2.3",
                  "2.4"
                ]
              },
              "audioUnchanged": {
                "type": "boolean",
                "description": "MD5 of the audio frames is identical before and after."
              },
              "durationSeconds": {
                "type": "number"
              },
              "outputBytes": {
                "type": "integer"
              },
              "artifact": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "artifactId",
                  "filename",
                  "mime",
                  "bytes",
                  "sha256",
                  "path"
                ],
                "properties": {
                  "artifactId": {
                    "type": "string"
                  },
                  "filename": {
                    "type": "string"
                  },
                  "mime": {
                    "type": "string"
                  },
                  "bytes": {
                    "type": "integer"
                  },
                  "sha256": {
                    "type": "string"
                  },
                  "path": {
                    "type": "string",
                    "description": "Download path on the same site (valid for about 2 hours)."
                  }
                }
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      }
    }
  }
}