Caption File Check
Parse WebVTT, SRT, or TTML for conformance, timing, overlaps, line length, and reading speed.
Should I use this
Quality & Safety
Based on automated analysis of tool definitions and protocol compliance.
Context Cost
This is the approximate number of tokens consumed each time the server's tools are loaded into a model's context. Higher counts reduce the attention available for other tasks.
Install
One-Click Install
Add this to your `claude_desktop_config.json` file:
{
"mcpServers": {
"caption-file-check": {
"url": "https://powmcp.com/caption-file-check/mcp"
}
}
}Remote endpoints
https://powmcp.com/caption-file-check/mcpstreamable-httpWhat it can do
Tool inventory
Tools (2)
🟢caption_check(url, file, profile)
Preflight one caption or subtitle file before delivery. Attach a WebVTT (.vtt), SRT (.srt), or TTML/IMSC (.ttml/.xml) caption file in chat or give a publicly fetchable URL and it downloads the artifact under an SSRF-guarded, 2 MB-capped fetch, detects the format by content and the byte encoding and BOM, then parses it with the real spec engine (the WebVTT spec parser, a dedicated SRT parser, or the imscJS TTML/IMSC profile engine) and returns deterministic evidence: pass/fail, cue count, structural spec and IMSC profile-conformance errors, overlapping / negative / out-of-order / empty cues, per-line length, and per-cue and summary reading speed (CPS) against a named platform profile (netflix-adult-20, netflix-children-17, youtube, ebu-tt). It reports only source-file conformance, timing, encoding, and reading-speed facts against a dated profile. It does not judge translation quality, transcription accuracy, or synchronization against the video. An arbitrary XML or text file that is not a caption track returns an explicit unsupported-format error. Fetching and parsing a full-length track can take up to 60 seconds. WebVTT limitation: the parser drops payload-less cues; cue counts, indices, timing checks and comparisons cover retained cues only, not those omitted cues.
Input Schema
{
"type": "object",
"properties": {
"url": {
"minLength": 1,
"maxLength": 2048,
"pattern": "^https?://",
"type": "string",
"description": "A publicly fetchable HTTP(S) URL of a WebVTT, SRT, or TTML/IMSC caption file, detected by content not extension. Provide either this or an attached file, never both. Query strings are allowed but never logged. Pasted caption bodies, data URLs, FTP/SFTP, and URLs needing credentials, headers, or cookies are not supported.\n\nSTRICT RULE: Caption check failed — provide either a caption URL or an attached caption file, not both\nSTRICT RULE: Caption check failed — provide a public caption URL or attach the caption file"
},
"file": {
"type": "object",
"required": [
"download_url",
"file_id"
],
"properties": {
"download_url": {
"type": "string",
"description": "Temporary authorized download URL supplied by ChatGPT; fetch it only while handling this tool call"
},
"file_id": {
"type": "string",
"description": "ChatGPT file id for the attached file"
},
"mime_type": {
"type": "string",
"description": "MIME type when ChatGPT knows it"
},
"file_name": {
"type": "string",
"description": "Original file name when ChatGPT knows it"
}
},
"description": "A caption file attached in chat (WebVTT, SRT, or TTML/IMSC), detected by content not extension. Provide either this or url, never both.",
"additionalProperties": false
},
"profile": {
"anyOf": [
{
"const": "netflix-adult-20",
"type": "string",
"description": "Named reading-speed profile to judge CPS and line length against. netflix-adult-20 (default, 20 CPS) and netflix-children-17 (17 CPS) are spec-backed; youtube and ebu-tt are advisory ~17 CPS heuristics."
},
{
"const": "netflix-children-17",
"type": "string",
"description": "Named reading-speed profile to judge CPS and line length against. netflix-adult-20 (default, 20 CPS) and netflix-children-17 (17 CPS) are spec-backed; youtube and ebu-tt are advisory ~17 CPS heuristics."
},
{
"const": "youtube",
"type": "string",
"description": "Named reading-speed profile to judge CPS and line length against. netflix-adult-20 (default, 20 CPS) and netflix-children-17 (17 CPS) are spec-backed; youtube and ebu-tt are advisory ~17 CPS heuristics."
},
{
"const": "ebu-tt",
"type": "string",
"description": "Named reading-speed profile to judge CPS and line length against. netflix-adult-20 (default, 20 CPS) and netflix-children-17 (17 CPS) are spec-backed; youtube and ebu-tt are advisory ~17 CPS heuristics."
}
],
"description": "Named reading-speed profile to judge CPS and line length against. netflix-adult-20 (default, 20 CPS) and netflix-children-17 (17 CPS) are spec-backed; youtube and ebu-tt are advisory ~17 CPS heuristics."
}
},
"additionalProperties": false
}Output Schema
{
"type": "object",
"properties": {
"url": {
"type": "string",
"description": "The checked caption source: the submitted URL query- and fragment-stripped, or the attached file's name"
},
"checkedAt": {
"type": "string",
"description": "ISO timestamp when the caption result was produced"
},
"detectedFormat": {
"type": "string",
"description": "webvtt, srt, or ttml (covers IMSC), detected by content"
},
"ttmlProfile": {
"type": "string",
"description": "IMSC/TTML profile designator declared in the file, when present"
},
"encoding": {
"type": "string",
"description": "Detected byte encoding of the caption file"
},
"bom": {
"type": "string",
"description": "Byte-order-mark detected: utf-8, utf-16le, utf-16be, or none"
},
"pass": {
"type": "boolean",
"description": "True when the file passes all checked format, timing, line-length and reading-speed criteria for the selected profile. False can include an advisory readability threshold breach, not just a specification error; this is not a platform-acceptance verdict"
},
"cueCount": {
"type": "number",
"description": "Number of caption cues retained for checking; payload-less WebVTT cues are omitted by the parser"
},
"rawCueCount": {
"type": "number",
"description": "Cues parsed before the 20,000-cue cap; excludes payload-less WebVTT cues dropped by the parser"
},
"profile": {
"type": "object",
"required": [
"id",
"date",
"label",
"maxCps",
"maxLineLength",
"advisory",
"source"
],
"properties": {
"id": {
"type": "string",
"description": "Identifier of the applied caption profile"
},
"date": {
"type": "string",
"description": "Review month recorded for the profile"
},
"label": {
"type": "string",
"description": "Display name of the applied caption profile"
},
"maxCps": {
"type": "number",
"description": "Maximum characters per second specified by the profile"
},
"maxLineLength": {
"type": "number",
"description": "Maximum characters per line specified by the profile"
},
"advisory": {
"type": "boolean",
"description": "The reading-speed limit is an industry heuristic, not a spec-mandated number"
},
"source": {
"type": "string",
"description": "Source or advisory basis recorded for the profile"
}
},
"description": "Reading-speed and line-length profile applied to the caption checks",
"additionalProperties": false
},
"timing": {
"type": "object",
"required": [
"checked",
"clean",
"overlapping",
"negative",
"outOfOrder",
"empty"
],
"properties": {
"checked": {
"type": "boolean",
"description": "Cue timing could be analysed (at least one cue)"
},
"clean": {
"type": "boolean",
"description": "Checked and no overlapping, negative, out-of-order, or empty retained cue found, distinguished from not-checked; omitted payload-less WebVTT cues are not assessed"
},
"overlapping": {
"type": "array",
"items": {
"type": "object",
"required": [
"cue",
"previousCue"
],
"properties": {
"cue": {
"type": "number",
"description": "Index of the affected caption cue"
},
"previousCue": {
"type": "number",
"description": "Index of the preceding overlapping cue"
}
},
"additionalProperties": false
},
"description": "Cues that start before the preceding cue ends"
},
"negative": {
"type": "array",
"items": {
"type": "object",
"required": [
"cue",
"durationMs"
],
"properties": {
"cue": {
"type": "number",
"description": "Index of the affected caption cue"
},
"durationMs": {
"type": "number",
"description": "Cue end time minus start time in milliseconds"
}
},
"additionalProperties": false
},
"description": "Cues whose end time is at or before their start time"
},
"outOfOrder": {
"type": "array",
"items": {
"type": "object",
"required": [
"cue"
],
"properties": {
"cue": {
"type": "number",
"description": "Index of the affected caption cue"
}
},
"additionalProperties": false
},
"description": "Cues that start before the preceding cue starts"
},
"empty": {
"type": "array",
"items": {
"type": "object",
"required": [
"cue"
],
"properties": {
"cue": {
"type": "number",
"description": "Index of the affected caption cue"
}
},
"additionalProperties": false
},
"description": "Cues whose text is empty after trimming whitespace"
}
},
"description": "Measured retained-cue timing and empty-text findings; WebVTT indices refer to retained cues, not original source positions",
"additionalProperties": false
},
"lineLength": {
"type": "object",
"required": [
"limit",
"maxObserved",
"overLimit"
],
"properties": {
"limit": {
"type": "number",
"description": "Profile maximum characters per line"
},
"maxObserved": {
"type": "number",
"description": "Largest character count observed on a caption line"
},
"overLimit": {
"type": "array",
"items": {
"type": "object",
"required": [
"cue",
"line",
"length"
],
"properties": {
"cue": {
"type": "number",
"description": "Index of the affected caption cue"
},
"line": {
"type": "number",
"description": "One-based line number within the cue"
},
"length": {
"type": "number",
"description": "Number of Unicode characters on the affected line"
}
},
"additionalProperties": false
},
"description": "Caption lines exceeding the profile character limit"
}
},
"description": "Per-line character counts checked against the profile limit",
"additionalProperties": false
},
"cps": {
"type": "object",
"required": [
"profileId",
"limit",
"advisory",
"measured",
"max",
"mean",
"breaches"
],
"properties": {
"profileId": {
"type": "string",
"description": "Identifier of the profile supplying the reading-speed limit"
},
"limit": {
"type": "number",
"description": "Profile maximum characters per second"
},
"advisory": {
"type": "boolean",
"description": "Whether the profile reading-speed limit is advisory"
},
"measured": {
"type": "boolean",
"description": "At least one cue had positive duration and text, distinguished from not-measured"
},
"max": {
"type": "number",
"description": "Highest per-cue characters-per-second"
},
"mean": {
"type": "number",
"description": "Mean characters per second across measured nonempty cues with positive duration"
},
"breaches": {
"type": "array",
"items": {
"type": "object",
"required": [
"cue",
"cps"
],
"properties": {
"cue": {
"type": "number",
"description": "Index of the affected caption cue"
},
"cps": {
"type": "number",
"description": "Measured reading speed for the cue in characters per second"
}
},
"additionalProperties": false
},
"description": "Cues whose reading speed exceeds the profile limit"
}
},
"description": "Per-cue and summary reading-speed measurements",
"additionalProperties": false
},
"structuralErrors": {
"type": "array",
"items": {
"type": "object",
"required": [
"severity",
"code",
"message"
],
"properties": {
"severity": {
"type": "string",
"description": "Severity assigned by the caption parser"
},
"code": {
"type": "string",
"description": "Machine-readable structural finding code"
},
"message": {
"type": "string",
"description": "Parser diagnostic describing the structural finding"
},
"cue": {
"type": "number",
"description": "Index of the affected caption cue"
}
},
"additionalProperties": false
},
"description": "Spec-parser and IMSC/TTML profile-conformance findings"
},
"structuralErrorCounts": {
"type": "object",
"required": [
"error",
"warning"
],
"properties": {
"error": {
"type": "number",
"description": "Number of error-severity structural findings"
},
"warning": {
"type": "number",
"description": "Number of warning-severity structural findings"
}
},
"description": "Counts of structural findings grouped by severity",
"additionalProperties": false
},
"specUsed": {
"type": "string",
"description": "The dated spec identifier the detected format was checked against"
},
"truncation": {
"type": "array",
"items": {
"type": "string",
"description": "Machine-checkable truncation markers, e.g. cue-cap"
},
"description": "Markers identifying checks truncated by configured limits"
}
},
"required": [
"url",
"checkedAt",
"detectedFormat",
"encoding",
"bom",
"pass",
"cueCount",
"rawCueCount",
"profile",
"timing",
"lineLength",
"cps",
"structuralErrors",
"structuralErrorCounts",
"specUsed",
"truncation"
],
"additionalProperties": false
}🟢caption_compare(urls, files, profile)
Compare exactly two caption or subtitle files under identical bounded checks: an original versus its translated track, before versus after a timing fix, or a format migration. Attach two WebVTT, SRT, or TTML/IMSC caption files in chat or give two publicly fetchable URLs and it runs the same SSRF-guarded, 2 MB-capped preflight as caption_check on each, then aligns them by cue index and reports side-by-side pass status, detected-format and encoding differences, the cue-count delta, timing drift and overlap differences, reading-speed (CPS) regressions, structural-error deltas, and a winner only when the measured checks separate the two. Use caption_check for a single file. It reports only source-file conformance, timing, encoding, and reading-speed facts against a dated profile: never translation quality, transcription accuracy, or sync against the video. Fetching and parsing two live files can take up to 60 seconds. WebVTT limitation: the parser drops payload-less cues; cue counts, indices, timing checks and comparisons cover retained cues only, not those omitted cues.
Input Schema
{
"type": "object",
"properties": {
"urls": {
"minItems": 2,
"maxItems": 2,
"type": "array",
"items": {
"minLength": 1,
"maxLength": 2048,
"pattern": "^https?://",
"type": "string",
"description": "A publicly fetchable HTTP(S) WebVTT, SRT, or TTML/IMSC caption URL, detected by content."
},
"description": "Exactly two public caption URLs to compare, in the order they should appear side by side (for example original then translated). Provide either this or files, never both.\n\nSTRICT RULE: Caption compare failed — provide either two caption URLs or two attached caption files, not both\nSTRICT RULE: Caption compare failed — provide two public caption URLs or attach two caption files"
},
"files": {
"minItems": 2,
"maxItems": 2,
"type": "array",
"items": {
"type": "object",
"required": [
"download_url",
"file_id"
],
"properties": {
"download_url": {
"type": "string",
"description": "Temporary authorized download URL supplied by ChatGPT; fetch it only while handling this tool call"
},
"file_id": {
"type": "string",
"description": "ChatGPT file id for the attached file"
},
"mime_type": {
"type": "string",
"description": "MIME type when ChatGPT knows it"
},
"file_name": {
"type": "string",
"description": "Original file name when ChatGPT knows it"
}
},
"description": "A caption file attached in chat (WebVTT, SRT, or TTML/IMSC), detected by content.",
"additionalProperties": false
},
"description": "Exactly two caption files attached in chat to compare, in the order they should appear side by side (for example original then translated). Provide either this or urls, never both."
},
"profile": {
"anyOf": [
{
"const": "netflix-adult-20",
"type": "string",
"description": "Named reading-speed profile applied to both tracks. netflix-adult-20 (default), netflix-children-17, youtube, ebu-tt."
},
{
"const": "netflix-children-17",
"type": "string",
"description": "Named reading-speed profile applied to both tracks. netflix-adult-20 (default), netflix-children-17, youtube, ebu-tt."
},
{
"const": "youtube",
"type": "string",
"description": "Named reading-speed profile applied to both tracks. netflix-adult-20 (default), netflix-children-17, youtube, ebu-tt."
},
{
"const": "ebu-tt",
"type": "string",
"description": "Named reading-speed profile applied to both tracks. netflix-adult-20 (default), netflix-children-17, youtube, ebu-tt."
}
],
"description": "Named reading-speed profile applied to both tracks. netflix-adult-20 (default), netflix-children-17, youtube, ebu-tt."
}
},
"description": "STRICT RULE: Caption compare failed — the two caption files are the same; provide two distinct caption files.",
"additionalProperties": false
}Output Schema
{
"type": "object",
"properties": {
"checkedAt": {
"type": "string",
"description": "ISO timestamp when the caption result was produced"
},
"profile": {
"type": "object",
"required": [
"id",
"date",
"label",
"maxCps",
"maxLineLength",
"advisory",
"source"
],
"properties": {
"id": {
"type": "string",
"description": "Identifier of the applied caption profile"
},
"date": {
"type": "string",
"description": "Review month recorded for the profile"
},
"label": {
"type": "string",
"description": "Display name of the applied caption profile"
},
"maxCps": {
"type": "number",
"description": "Maximum characters per second specified by the profile"
},
"maxLineLength": {
"type": "number",
"description": "Maximum characters per line specified by the profile"
},
"advisory": {
"type": "boolean",
"description": "The reading-speed limit is an industry heuristic, not a spec-mandated number"
},
"source": {
"type": "string",
"description": "Source or advisory basis recorded for the profile"
}
},
"description": "Reading-speed and line-length profile applied to the caption checks",
"additionalProperties": false
},
"tracks": {
"type": "array",
"items": {
"type": "object",
"required": [
"url",
"ok"
],
"properties": {
"url": {
"type": "string",
"description": "The checked caption source: the submitted URL query- and fragment-stripped, or the attached file's name"
},
"ok": {
"type": "boolean",
"description": "Whether the caption file could be fetched and preflighted"
},
"failed": {
"type": "string",
"description": "Reason the caption file could not be preflighted"
},
"detectedFormat": {
"type": "string",
"description": "Caption format detected from file content"
},
"encoding": {
"type": "string",
"description": "Detected byte encoding of the caption file"
},
"bom": {
"type": "string",
"description": "Detected byte-order mark, or none"
},
"pass": {
"type": "boolean",
"description": "Whether the track passes structural, timing, line-length, and reading-speed checks"
},
"cueCount": {
"type": "number",
"description": "Number of caption cues retained for checking"
},
"timing": {
"type": "object",
"required": [
"checked",
"clean",
"overlapping",
"negative",
"outOfOrder",
"empty"
],
"properties": {
"checked": {
"type": "boolean",
"description": "Cue timing could be analysed (at least one cue)"
},
"clean": {
"type": "boolean",
"description": "Checked and no overlapping, negative, out-of-order, or empty cue found, distinguished from not-checked"
},
"overlapping": {
"type": "array",
"items": {
"type": "object",
"required": [
"cue",
"previousCue"
],
"properties": {
"cue": {
"type": "number",
"description": "Index of the affected caption cue"
},
"previousCue": {
"type": "number",
"description": "Index of the preceding overlapping cue"
}
},
"additionalProperties": false
},
"description": "Cues that start before the preceding cue ends"
},
"negative": {
"type": "array",
"items": {
"type": "object",
"required": [
"cue",
"durationMs"
],
"properties": {
"cue": {
"type": "number",
"description": "Index of the affected caption cue"
},
"durationMs": {
"type": "number",
"description": "Cue end time minus start time in milliseconds"
}
},
"additionalProperties": false
},
"description": "Cues whose end time is at or before their start time"
},
"outOfOrder": {
"type": "array",
"items": {
"type": "object",
"required": [
"cue"
],
"properties": {
"cue": {
"type": "number",
"description": "Index of the affected caption cue"
}
},
"additionalProperties": false
},
"description": "Cues that start before the preceding cue starts"
},
"empty": {
"type": "array",
"items": {
"type": "object",
"required": [
"cue"
],
"properties": {
"cue": {
"type": "number",
"description": "Index of the affected caption cue"
}
},
"additionalProperties": false
},
"description": "Cues whose text is empty after trimming whitespace"
}
},
"description": "Measured cue timing and empty-text findings",
"additionalProperties": false
},
"lineLength": {
"type": "object",
"required": [
"limit",
"maxObserved",
"overLimit"
],
"properties": {
"limit": {
"type": "number",
"description": "Profile maximum characters per line"
},
"maxObserved": {
"type": "number",
"description": "Largest character count observed on a caption line"
},
"overLimit": {
"type": "array",
"items": {
"type": "object",
"required": [
"cue",
"line",
"length"
],
"properties": {
"cue": {
"type": "number",
"description": "Index of the affected caption cue"
},
"line": {
"type": "number",
"description": "One-based line number within the cue"
},
"length": {
"type": "number",
"description": "Number of Unicode characters on the affected line"
}
},
"additionalProperties": false
},
"description": "Caption lines exceeding the profile character limit"
}
},
"description": "Per-line character counts checked against the profile limit",
"additionalProperties": false
},
"cps": {
"type": "object",
"required": [
"profileId",
"limit",
"advisory",
"measured",
"max",
"mean",
"breaches"
],
"properties": {
"profileId": {
"type": "string",
"description": "Identifier of the profile supplying the reading-speed limit"
},
"limit": {
"type": "number",
"description": "Profile maximum characters per second"
},
"advisory": {
"type": "boolean",
"description": "Whether the profile reading-speed limit is advisory"
},
"measured": {
"type": "boolean",
"description": "At least one cue had positive duration and text, distinguished from not-measured"
},
"max": {
"type": "number",
"description": "Highest per-cue characters-per-second"
},
"mean": {
"type": "number",
"description": "Mean characters per second across measured nonempty cues with positive duration"
},
"breaches": {
"type": "array",
"items": {
"type": "object",
"required": [
"cue",
"cps"
],
"properties": {
"cue": {
"type": "number",
"description": "Index of the affected caption cue"
},
"cps": {
"type": "number",
"description": "Measured reading speed for the cue in characters per second"
}
},
"additionalProperties": false
},
"description": "Cues whose reading speed exceeds the profile limit"
}
},
"description": "Per-cue and summary reading-speed measurements",
"additionalProperties": false
},
"structuralErrorCounts": {
"type": "object",
"required": [
"error",
"warning"
],
"properties": {
"error": {
"type": "number",
"description": "Number of error-severity structural findings"
},
"warning": {
"type": "number",
"description": "Number of warning-severity structural findings"
}
},
"description": "Counts of structural findings grouped by severity",
"additionalProperties": false
}
},
"additionalProperties": false
},
"description": "The two tracks in input order"
},
"comparison": {
"type": "object",
"required": [
"cueCountDelta",
"formatDiffers",
"encodingDiffers",
"passDiffers",
"timingDrift",
"overlapDelta",
"cpsRegression",
"structuralErrorDelta"
],
"properties": {
"cueCountDelta": {
"type": "number",
"description": "Second track cue count minus first"
},
"formatDiffers": {
"type": "boolean",
"description": "Whether the detected caption formats differ"
},
"encodingDiffers": {
"type": "boolean",
"description": "Whether the detected byte encodings differ"
},
"passDiffers": {
"type": "boolean",
"description": "Whether the two caption pass results differ"
},
"timingDrift": {
"type": "object",
"required": [
"alignedCues",
"maxStartDriftMs",
"meanStartDriftMs",
"driftingCues"
],
"properties": {
"alignedCues": {
"type": "number",
"description": "Cue positions compared by index, min of the two counts"
},
"maxStartDriftMs": {
"type": "number",
"description": "Largest absolute cue-start drift in milliseconds"
},
"meanStartDriftMs": {
"type": "number",
"description": "Mean absolute cue-start drift in milliseconds"
},
"driftingCues": {
"type": "number",
"description": "Aligned positions whose start times differ by more than 500 ms"
}
},
"description": "Absolute cue-start drift across positions aligned by cue index",
"additionalProperties": false
},
"overlapDelta": {
"type": "number",
"description": "Second track overlapping-cue count minus first"
},
"cpsRegression": {
"type": "object",
"required": [
"firstMax",
"secondMax",
"delta"
],
"properties": {
"firstMax": {
"type": "number",
"description": "Maximum reading speed of the first track in characters per second"
},
"secondMax": {
"type": "number",
"description": "Maximum reading speed of the second track in characters per second"
},
"delta": {
"type": "number",
"description": "Second track max CPS minus first: positive means the second reads faster"
}
},
"description": "Change in maximum reading speed from the first track to the second",
"additionalProperties": false
},
"structuralErrorDelta": {
"type": "object",
"required": [
"error",
"warning"
],
"properties": {
"error": {
"type": "number",
"description": "Second-track structural error count minus first-track count"
},
"warning": {
"type": "number",
"description": "Second-track structural warning count minus first-track count"
}
},
"description": "Second-track structural finding counts minus first-track counts",
"additionalProperties": false
}
},
"description": "Measured differences between the two successfully preflighted tracks",
"additionalProperties": false
},
"winner": {
"type": "object",
"required": [
"url",
"reason"
],
"properties": {
"url": {
"type": "string",
"description": "Reported source identifier of the track with fewer measured problems"
},
"reason": {
"type": "string",
"description": "Measured findings supporting the fewer-problems track"
}
},
"description": "Track with fewer weighted structural, timing, reading-speed, and line-length problems",
"additionalProperties": false
},
"notes": {
"type": "array",
"items": {
"type": "string"
},
"description": "Notes about incomplete checks or completion under identical limits"
}
},
"required": [
"checkedAt",
"profile",
"tracks",
"notes"
],
"additionalProperties": false
}Community
Evidence