Fix subtitles that are out of sync, right in the chat.
Maintain this server? Claim it
Call this server's tools from your browser. Nothing to install.
Requests go through mcptry because browsers can't call most MCP servers directly. Header values are sent to the server for that request only and are never stored or logged.
Tool list from our last check. Connect live to refresh it.
Use this when the user asks whether an SRT or VTT subtitle file has problems, or wants a report before fixing it: overlapping cues, zero or negative durations, cues out of order, SRT numbering gaps, empty cues, cues too fast to read (characters per second above max_cps, default 20) and lines longer than max_line_chars (default 42). Takes one attached .srt or .vtt file or the subtitle text. Does not make a file and does not change the subtitles; fix_subtitles does that. Does not check spelling, translation or sync with the audio.
The subtitle file: one .srt or .vtt file in UTF-8 or UTF-16 with a byte order mark, e.g. movie.srt.
Reading speed limit in characters per second, 5 to 60, e.g. 17. Default 20.
Instead of a file: the subtitle text itself, e.g. "1\n00:00:01,000 --> 00:00:03,000\nHello". Use either file or subtitle_text.
Longest line in characters, 20 to 100, e.g. 42 (default).
Pick your client. Values in capitals, like YOUR_TOKEN, are yours to fill in.
Run in a terminal
claude mcp add --transport http subtitle-fix https://subtitle-fix.zovo.one/mcp
Use this when the user asks whether an SRT or VTT subtitle file has problems, or wants a report before fixing it: overlapping cues, zero or negative durations, cues out of order, SRT numbering gaps, empty cues, cues too fast to read (characters per second above max_cps, default 20) and lines longer than max_line_chars (default 42). Takes one attached .srt or .vtt file or the subtitle text. Does not make a file and does not change the subtitles; fix_subtitles does that. Does not check spelling, translation or sync with the audio.
| Argument | Type | Description |
|---|---|---|
| file | object | The subtitle file: one .srt or .vtt file in UTF-8 or UTF-16 with a byte order mark, e.g. movie.srt. |
| max_cps | number | Reading speed limit in characters per second, 5 to 60, e.g. 17. Default 20. |
| subtitle_text | string | Instead of a file: the subtitle text itself, e.g. "1\n00:00:01,000 --> 00:00:03,000\nHello". Use either file or subtitle_text. |
| max_line_chars | integer | Longest line in characters, 20 to 100, e.g. 42 (default). |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"file": {
"type": "object",
"required": [
"download_url",
"file_id"
],
"properties": {
"file_id": {
"type": "string",
"description": "ChatGPT file id, e.g. file_abc123."
},
"file_name": {
"type": "string",
"description": "Original file name if known, e.g. statement.pdf."
},
"mime_type": {
"type": "string",
"description": "Media type if known, e.g. application/pdf."
},
"download_url": {
"type": "string",
"description": "Temporary download link for the file, supplied by ChatGPT."
}
},
"description": "The subtitle file: one .srt or .vtt file in UTF-8 or UTF-16 with a byte order mark, e.g. movie.srt."
},
"max_cps": {
"type": "number",
"description": "Reading speed limit in characters per second, 5 to 60, e.g. 17. Default 20."
},
"subtitle_text": {
"type": "string",
"maxLength": 2097152,
"description": "Instead of a file: the subtitle text itself, e.g. \"1\\n00:00:01,000 --> 00:00:03,000\\nHello\". Use either file or subtitle_text."
},
"max_line_chars": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "Longest line in characters, 20 to 100, e.g. 42 (default)."
}
}
}Use this when the user wants to fix subtitle timing or convert subtitles: shift an SRT or VTT file earlier or later, convert it from one frame rate to another (23.976, 24, 25, 29.97, 30, 50, 59.94, 60), sync it on two cues, trim overlapping cues, give short cues a minimum duration, strip formatting tags, renumber, or convert SRT to WebVTT and back. Takes one attached .srt or .vtt file (or the subtitle text) and returns the fixed file and a CSV change log with old and new times per cue. Times are whole milliseconds, rounded half up. Does not listen to audio or find the right offset by itself, does not translate or edit the words, and does not read SSA/ASS files.
| Argument | Type | Description |
|---|---|---|
| file | object | The subtitle file: one .srt or .vtt file in UTF-8 or UTF-16 with a byte order mark, e.g. movie.srt. |
| sync | object | Two-point sync: cue_a should start at time_a and cue_b at time_b; all times are mapped on that straight line. Do not combine with shift_ms or frame rates. |
| gap_ms | integer | Gap kept before the next cue when fixing overlaps or extending cues, 0 to 1000 ms, e.g. 1 (default). |
| to_fps | any | Frame rate of the video they should match, e.g. 23.976. One of 23.976, 24, 25, 29.97, 30, 50, 59.94 or 60. new time = old time x from_fps / to_fps. |
| from_fps | any | Frame rate the subtitles were timed for, e.g. 25. One of 23.976, 24, 25, 29.97, 30, 50, 59.94 or 60. Use with to_fps. |
We read every tool's name, description and inputs the way the model will, looking for instructions hidden from you. A clean result means no warning signs, not a guarantee. Scanned Nov 8, 2026.
| renumber |
| boolean |
| SRT output: true (default) numbers cues 1, 2, 3 in output order; false keeps the numbers as written. |
| shift_ms | integer | Move all cues by this many milliseconds: positive = later, negative = earlier, e.g. 2500 (2.5 s later) or -1200. Limit 24 hours. |
| strip_tags | boolean | true removes formatting tags such as <i>, <b>, <u>, <font>, WebVTT <c>/<v> tags and {\an8} codes from the text. Default false. |
| fix_overlaps | boolean | true: when a cue ends after the next cue starts, or less than gap_ms before it, its end moves to gap_ms before that start. Default false. |
| line_endings | string | Line endings of the output, e.g. crlf. Default same as the input (CRLF, LF, or CR for old Mac files). |
| output_format | string | Output format, e.g. vtt to convert SRT to WebVTT. Default same as the input. |
| sort_by_start | boolean | true writes cues in start-time order (stable). Default false keeps the file order. |
| subtitle_text | string | Instead of a file: the subtitle text itself, e.g. "1\n00:00:01,000 --> 00:00:03,000\nHello". Use either file or subtitle_text. |
| min_duration_ms | integer | Make short cues last at least this long, up to gap_ms before the next cue, e.g. 1000. 0 (default) = off. Limit 10000. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"file": {
"type": "object",
"required": [
"download_url",
"file_id"
],
"properties": {
"file_id": {
"type": "string",
"description": "ChatGPT file id, e.g. file_abc123."
},
"file_name": {
"type": "string",
"description": "Original file name if known, e.g. statement.pdf."
},
"mime_type": {
"type": "string",
"description": "Media type if known, e.g. application/pdf."
},
"download_url": {
"type": "string",
"description": "Temporary download link for the file, supplied by ChatGPT."
}
},
"description": "The subtitle file: one .srt or .vtt file in UTF-8 or UTF-16 with a byte order mark, e.g. movie.srt."
},
"sync": {
"type": "object",
"required": [
"cue_a",
"time_a",
"cue_b",
"time_b"
],
"properties": {
"cue_a": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "First reference cue, counted in file order (1 = first cue), e.g. 1."
},
"cue_b": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "Second reference cue, far from the first, e.g. 812 (the last cue)."
},
"time_a": {
"type": "string",
"maxLength": 20,
"description": "When cue_a should start, HH:MM:SS,mmm, e.g. \"00:00:41,200\"."
},
"time_b": {
"type": "string",
"maxLength": 20,
"description": "When cue_b should start, e.g. \"01:52:07,900\"."
}
},
"description": "Two-point sync: cue_a should start at time_a and cue_b at time_b; all times are mapped on that straight line. Do not combine with shift_ms or frame rates."
},
"gap_ms": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "Gap kept before the next cue when fixing overlaps or extending cues, 0 to 1000 ms, e.g. 1 (default)."
},
"to_fps": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"maxLength": 12
}
],
"description": "Frame rate of the video they should match, e.g. 23.976. One of 23.976, 24, 25, 29.97, 30, 50, 59.94 or 60. new time = old time x from_fps / to_fps."
},
"from_fps": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"maxLength": 12
}
],
"description": "Frame rate the subtitles were timed for, e.g. 25. One of 23.976, 24, 25, 29.97, 30, 50, 59.94 or 60. Use with to_fps."
},
"renumber": {
"type": "boolean",
"description": "SRT output: true (default) numbers cues 1, 2, 3 in output order; false keeps the numbers as written."
},
"shift_ms": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "Move all cues by this many milliseconds: positive = later, negative = earlier, e.g. 2500 (2.5 s later) or -1200. Limit 24 hours."
},
"strip_tags": {
"type": "boolean",
"description": "true removes formatting tags such as <i>, <b>, <u>, <font>, WebVTT <c>/<v> tags and {\\an8} codes from the text. Default false."
},
"fix_overlaps": {
"type": "boolean",
"description": "true: when a cue ends after the next cue starts, or less than gap_ms before it, its end moves to gap_ms before that start. Default false."
},
"line_endings": {
"enum": [
"same",
"crlf",
"lf"
],
"type": "string",
"description": "Line endings of the output, e.g. crlf. Default same as the input (CRLF, LF, or CR for old Mac files)."
},
"output_format": {
"enum": [
"same",
"srt",
"vtt"
],
"type": "string",
"description": "Output format, e.g. vtt to convert SRT to WebVTT. Default same as the input."
},
"sort_by_start": {
"type": "boolean",
"description": "true writes cues in start-time order (stable). Default false keeps the file order."
},
"subtitle_text": {
"type": "string",
"maxLength": 2097152,
"description": "Instead of a file: the subtitle text itself, e.g. \"1\\n00:00:01,000 --> 00:00:03,000\\nHello\". Use either file or subtitle_text."
},
"min_duration_ms": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "Make short cues last at least this long, up to gap_ms before the next cue, e.g. 1000. 0 (default) = off. Limit 10000."
}
}
}