mcp-video-analyzer
Transforme qualquer vídeo — YouTube, Instagram, TikTok, Loom, URLs diretos ou arquivos locais — em transcrições, quadros-chave, texto OCR e metadados para agentes de IA.
Documentação
mcp-video-analyzer
Transforme qualquer vídeo — YouTube, Instagram, TikTok, Loom, X, Vimeo, links diretos, arquivos locais — em transcrições, quadros-chave, texto OCR e metadados para agentes de IA.
Nenhum MCP de vídeo existente combina transcrições + quadros visuais + metadados em uma única ferramenta. Este combina — em Loom, nas principais plataformas yt-dlp (YouTube/Vimeo/TikTok/Instagram/X/Twitch/Dailymotion/Facebook), URLs de vídeo diretos e arquivos locais.
Quer um pipeline completo, não apenas uma ferramenta? social-knowledge-base é construído sobre este servidor — ele baixa contas inteiras de criadores do Instagram (reels, stories, destaques), transcreve-as e transforma o resultado em uma base de conhecimento pesquisável e consultável via RAG, com notas geradas por IA. Use este MCP quando quiser análise por vídeo dentro de um agente; use social-knowledge-base quando quiser arquivar e consultar uma conta inteira.
Instalação
Pré-requisitos
- Node.js 22.12+ — necessário para executar o servidor via
npx - yt-dlp — obrigatório para URLs do YouTube/Vimeo/TikTok/Instagram/X/Twitch/Dailymotion/Facebook; opcional para todo o resto (melhora a qualidade do download do Loom). Instale com
pip install yt-dlp - Chrome/Chromium (opcional) — alternativa para extração de quadros se o yt-dlp não estiver disponível
Sem yt-dlp ou Chrome, URLs diretos e arquivos locais ainda geram quadros — o
ffmpeg-staticincluído faz a extração, e o Loom usa o download do próprio CDN como alternativa. URLs de plataformas (YouTube etc.) degradam para um aviso claro de "instale o yt-dlp". Transcrições, metadados e comentários nunca exigem nenhum dos dois.
Há três formas de acesso: o plugin /video (Claude Code — comando de barra + servidor MCP configurado automaticamente), uma configuração MCP server simples (qualquer cliente MCP) ou a skill portátil + CLI (Codex, Cursor, Copilot e qualquer agente com shell — sem necessidade de MCP).
Claude Code — plugin /video (recomendado)
/plugin marketplace add guimatheus92/mcp-video-analyzer
/plugin install video@mcp-video-analyzer
Isso adiciona o comando de barra /video e registra automaticamente o servidor MCP — sem necessidade de claude mcp add:
/video https://youtu.be/jNQXAC9IVRw what happens at 0:10?
/video ~/Movies/screen-recording.mp4 when does the UI break?
Outros agentes — Codex, Cursor, Copilot, Gemini CLI, …
npx skills add guimatheus92/mcp-video-analyzer
Instala a skill video (formato Agent Skills) em todos os agentes detectados na sua máquina. Agentes sem o servidor MCP configurado usam automaticamente a CLI incluída — zero configuração.
Claude Code (somente MCP)
claude mcp add video-analyzer -- npx mcp-video-analyzer@latest
Depois reinicie o Claude Code ou inicie uma nova conversa.
VS Code / Cursor
Adicione ao seu arquivo de configurações MCP:
- VS Code:
File → Preferences → Settings → search "MCP"ou edite~/.vscode/mcp.json/%APPDATA%\Code\User\mcp.json(Windows) - Cursor:
Settings → MCP Servers → Add
{
"servers": {
"mcp-video-analyzer": {
"type": "stdio",
"command": "npx",
"args": ["mcp-video-analyzer@latest"]
}
}
}
Depois recarregue a janela (Ctrl+Shift+P → "Developer: Reload Window").
Claude Desktop
Adicione ao arquivo de configuração do Claude Desktop:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"video-analyzer": {
"command": "npx",
"args": ["mcp-video-analyzer@latest"]
}
}
}
Depois reinicie o Claude Desktop.
CLI (uso único, sem cliente MCP)
O mesmo mecanismo é exposto como um comando de uso único — é isso que a skill video usa em agentes sem MCP, e funciona de forma independente em qualquer terminal:
npx -y mcp-video-analyzer@latest analyze "https://youtu.be/jNQXAC9IVRw"
O stdout é um único documento JSON — metadata, transcript, ocrResults, timeline, warnings, frameCount e frames como entradas { time, filePath, mimeType } apontando para quadros-chave JPEG copiados para --out (padrão: o diretório de cache por usuário — %LOCALAPPDATA% no Windows, ~/Library/Caches no macOS, $XDG_CACHE_HOME ou ~/.cache no Linux — em mcp-video-analyzer/<url-hash>/; defina MCP_CACHE_DIR para um caminho absoluto para realocá-lo). Diferente do diretório temporário onde costumava ficar, nada remove esse local, então os quadros persistem até você excluí-los — os diretórios são criados 0700. O progresso é transmitido no stderr, então stdout pode ser canalizado diretamente para um analisador JSON. Falhas parciais ficam em warnings com código de saída 0; apenas falhas graves saem com código 1.
| Flag | Descrição |
|---|---|
--detail <level> | brief (metadados + transcrição, sem quadros), standard (padrão), detailed |
--max-frames <n> | Máximo de quadros-chave, 1–60 (o padrão se adapta à duração) |
--max-width <px> | Limite de largura para quadros emitidos (padrão 800, ou MCP_FRAME_MAX_WIDTH); 0 mantém a resolução original — veja Tamanho do quadro |
--fields <list> | Filtro de saída — subconjunto separado por vírgulas: metadata,transcript,frames,comments,chapters,ocrResults,timeline,aiSummary. Filtra apenas o JSON emitido; use --detail brief para realmente pular download/extração de quadros |
--force-refresh | Ignora o cache e reanalisa |
--ocr-language <codes> | Idiomas do Tesseract (padrão eng+por) |
--model <name> / --language <code> | Substituições do Whisper para a transcrição alternativa |
--out <dir> | Onde as imagens dos quadros são copiadas |
Execute sem argumentos (npx mcp-video-analyzer@latest) para iniciar o servidor MCP stdio — a CLI é puramente aditiva.
Verifique se funciona
Após a instalação, pergunte ao seu assistente de IA:
Analyze this video: https://www.youtube.com/watch?v=jNQXAC9IVRw
(também funciona com um link do Instagram/TikTok/Loom, uma URL .mp4 direta ou um caminho de arquivo local). Se o servidor estiver conectado, ele chamará automaticamente a ferramenta analyze_video.
Ferramentas
Oito ferramentas — a IA escolhe a mais barata para a tarefa e a chama automaticamente. Clique em qualquer ferramenta para expandir seus parâmetros e exemplos.
| Ferramenta | O que faz |
|---|---|
analyze_video | Análise completa: transcrição + quadros-chave + OCR + linha do tempo + metadados |
analyze_videos | Versão em lote, um resultado estruturado por fonte (retomável) |
get_transcript | Somente transcrição (legendas nativas ou alternativa Whisper) |
get_metadata | Metadados + comentários + capítulos, sem download |
get_frames | Somente quadros-chave (mudança de cena ou denso 1 fps) |
analyze_moment | Análise aprofundada de um intervalo de tempo (rajada de quadros + transcrição + OCR) |
get_frame_at | Quadro único em um timestamp |
get_frame_burst | N quadros em uma janela estreita (movimento/animação) |
analyze_video — análise completa de vídeo
Extrai tudo de uma URL de vídeo em uma única chamada:
> Analyze this video: https://www.youtube.com/watch?v=abc123...
Retorna:
- Transcrição com timestamps e falantes
- Quadros-chave extraídos via detecção de mudança de cena (deduplicados automaticamente). Para clipes estáticos sem cortes de cena — por exemplo, Reels/Stories com cabeça falante onde apenas uma sobreposição de texto na tela muda — ele automaticamente usa amostragem temporal uniforme para que você ainda receba quadros (e OCR) em vez de um resultado vazio.
- Texto OCR extraído dos quadros (código, mensagens de erro, texto de interface, preços/datas/CTAs visíveis na tela)
- Linha do tempo anotada mesclando transcrição + quadros + OCR em uma visão unificada de "o que aconteceu quando"
- Metadados (título, duração, plataforma)
- Comentários dos espectadores
- Capítulos e resumo de IA (quando disponíveis)
A IA chamará automaticamente esta ferramenta ao ver uma URL de vídeo — sem necessidade de pedir.
Opções:
detail— profundidade da análise:"brief"(metadados + transcrição truncada, sem quadros),"standard"(padrão),"detailed"(amostragem densa, mais quadros)fields— array de campos específicos para retornar, ex.:["metadata", "transcript"]. Disponíveis:metadata,transcript,frames,comments,chapters,ocrResults,timeline,aiSummarymaxFrames(1-60) — limite de quadros extraídos. O padrão escala com a duração do vídeo no detalhestandard(~12 para ≤30s até 60 para >10min); fixo em 60 nodetailed, 0 nobrief. Um valor explícito sempre vencethreshold(0.0-1.0, padrão 0.1) — sensibilidade à mudança de cenaforceRefresh— ignora o cache e reanalisaskipFrames— pula a extração de quadros para análise somente de transcriçãomodel/language/initialPrompt— substituições do Whisper por chamada para a transcrição alternativa (substituiWHISPER_MODEL/WHISPER_LANGUAGE/WHISPER_PROMPTapenas para esta chamada — escolha um modelo mais pesado ou um glossário de domínio para um clipe difícil sem reiniciar o servidor)
analyze_videos — análise em lote
> Analyze every .mp4 in this folder
Executa analyze_video sobre uma lista de sources com um limite de concurrency (padrão 2), retornando um resultado estruturado por fonte — contagens + avisos em caso de sucesso, ou um error por item em caso de falha (um arquivo ruim nunca aborta o lote). As imagens dos quadros não são embutidas e a transcrição/OCR/linha do tempo completos são retornados apenas quando fields está definido; caso contrário, você recebe contagens. Combine com MCP_WRITE_SIDECARS=1 (abaixo) para que o resultado de cada vídeo persista no disco e uma nova execução retome em vez de recalcular.
get_transcript — somente transcrição
> Get the transcript from this video
Extração rápida de transcrição. Usa transcrição Whisper como alternativa quando não há transcrição nativa. Aceita as mesmas substituições model / language / initialPrompt por chamada que analyze_video.
get_metadata — somente metadados
> What's this video about?
Retorna metadados, comentários, capítulos e resumo de IA sem baixar o vídeo.
get_frames — somente quadros
> Extract frames from this video with dense sampling
Dois modos:
- Detecção de mudança de cena (padrão) — captura transições visuais
- Amostragem densa (
dense: true) — 1 quadro/seg para cobertura completa
analyze_moment — análise aprofundada de um intervalo de tempo
> Analyze what happens between 1:30 and 2:00 in this video
Combina extração de rajada de quadros + transcrição filtrada + OCR + linha do tempo anotada para um segmento focado. Use quando precisar entender exatamente o que acontece em um momento específico.
get_frame_at — quadro único em um timestamp
> Show me the frame at 1:23 in this video
A IA lê a transcrição, identifica um momento crítico e solicita o quadro exato para ver o que está na tela.
get_frame_burst — N quadros em um intervalo de tempo
> Show me 10 frames between 0:15 and 0:17 of this video
Para movimento, vibração, animações ou rolagem rápida — o modo rajada captura N quadros em uma janela estreita para que a IA possa ver mudanças quadro a quadro.
Níveis de Detalhe
| Nível | Quadros | Transcrição | OCR | Linha do tempo | Caso de uso |
|---|---|---|---|---|---|
brief | Nenhum | Primeiras 10 entradas | Não | Não | Verificação rápida — sobre o que é este vídeo? |
standard | Adaptativo à duração: ~12 (≤30s) até 60 (>10min), mudança de cena | Completa | Sim | Sim | Padrão — análise completa |
detailed | Até 60 (1fps denso) | Completa | Sim | Sim | Análise profunda — cada segundo capturado |
Cache
Os resultados são armazenados em cache na memória por 10 minutos. Chamadas subsequentes com a mesma URL e opções retornam instantaneamente. Use forceRefresh: true para ignorar o cache. skipFrames faz parte do cache e da chave do sidecar, então uma análise apenas de transcrição e uma com quadros da mesma URL nunca respondem uma pela outra.
Sidecars persistentes (processamento em lote retomável)
O cache em memória é perdido ao reiniciar, o que torna o reprocessamento de um grande corpus local custoso. Defina MCP_WRITE_SIDECARS=1 para também persistir resultados ao lado de cada vídeo local para que o trabalho sobreviva a reinicializações e possa ser retomado:
<stem>.vtt— a transcrição, somente quando foi gerada pelo fallback Whisper (um<stem>.vttexistente do seu próprio pipeline nunca é sobrescrito). Uma chamada posterior o reutiliza via leitor de sidecar normal e ignora o Whisper completamente.<stem>.analysis.json+<stem>.frames/— o resultado completo (quadros + OCR + linha do tempo), chaveado pelomtime:sizedo vídeo e pelos parâmetros de análise. Em uma chamada posterior com carimbo + parâmetros correspondentes, o resultado é retornado diretamente do disco (sem extração, sem OCR).
Isso torna o analyze_videos sobre milhares de arquivos retomável, e permite que um pipeline externo de transcrição por GPU e este MCP compartilhem resultados através do sistema de arquivos: o pipeline escreve <stem>.vtt, e o MCP o utiliza em vez de executar o Whisper.
Fontes Suportadas
| Fonte | Transcrição | Metadados | Comentários | Quadros | Autenticação |
|---|---|---|---|---|---|
| Loom | Sim | Sim | Sim | Sim (geralmente precisa de yt-dlp — veja nota) | Nenhuma |
| YouTube / Vimeo / TikTok / Instagram / X / Twitch / Dailymotion / Facebook | Legendas nativas (enviadas > geradas automaticamente) ou fallback Whisper | Sim (título, duração, uploader, visualizações, capítulos, data de upload) | Não | Sim (limitado a 1080p) | yt-dlp instalado; cookies para Instagram / restrito por idade (veja abaixo) |
| URL direta (.mp4, .mov, .mkv, .webm, …) | Não | Somente duração | Não | Sim | Nenhuma |
| URL direta + TwelveLabs | Sim (Pegasus, melhor esforço) | Piso de duração + título | Não | Sim | TWELVELABS_API_KEY |
Arquivo local (caminho absoluto ou URI file://) | Sidecar .vtt/.srt ou fallback Whisper | Sondado via ffmpeg (duração, dimensões, codec, presença de áudio) | Não | Sim | Nenhuma |
Quadros Loom: transcrição, metadados e comentários vêm diretamente da API do Loom sem ferramentas extras. A extração de quadros é diferente — o Loom serve a maioria dos vídeos como streams DASH separados de vídeo+áudio, que apenas yt-dlp (
pip install yt-dlp) busca e mescla. A mesclagem usa offmpeg-staticincluído, então nenhum ffmpeg do sistema é necessário. Sem yt-dlp, um fallback de CDN direto ainda cobre alguns vídeos; quando não consegue, você recebe transcrição + metadados + comentários além de um aviso explicando por que os quadros estão ausentes.Arquivos locais: passe um caminho absoluto (ex.:
/Users/you/clip.mp4) ou uma URIfile://como argumentourlpara qualquer ferramenta. Caminhos relativos são rejeitados — o diretório de trabalho do servidor é imprevisível a partir do cliente MCP. Observe que qualquer chamador do servidor MCP pode pedir que ele leia qualquer arquivo ao qual o processo do servidor tenha acesso.Transcrições sidecar: se um
clip.vtt,clip.srt,clip.en.vtt, etc. estiver ao lado declip.mp4, ele é usado como transcrição automaticamente — sem ida e volta ao Whisper. SRT é convertido para VTT em memória.Legendas incorporadas: se nenhum sidecar for encontrado e o contêiner tiver um stream de legenda incorporado (comum em
.mkv/.mov/.mp4de gravadores de tela), ele é transmuxado para VTT via ffmpeg e usado como transcrição.Extensões reconhecidas (arquivos locais e URLs diretas):
.mp4.mov.mkv.webm.avi.m4v.wmv.flv.mpeg.mpg.m2ts.mts.3gp.ogv. A extensão apenas controla o roteamento — o ffmpeg faz a demuxagem real, então a maioria dos contêineres comuns funciona..tsé excluído para evitar colisão com arquivos-fonte TypeScript.
URLs de plataformas via yt-dlp (YouTube, Instagram, TikTok, …)
Páginas de vídeo único em grandes plataformas passam por yt-dlp (pip install yt-dlp — necessário para essas URLs). Playlists, canais e páginas de perfil são rejeitados por design; passe URLs de vídeo individuais (agrupe-as com analyze_videos).
- Transcrição: legendas nativas são preferidas e gratuitas — legendas enviadas primeiro, legendas geradas automaticamente como fallback (duplicação de janela deslizante é colapsada).
WHISPER_LANGUAGE(ex.:pt) também é usado para escolher o idioma da legenda. Vídeos sem legendas caem na cadeia normal do Whisper. - Metadados: título, duração, uploader/canal, contagem de visualizações, data de upload e capítulos — sem necessidade de download.
- Download: limitado a 1080p (quadros/OCR não precisam de mais), streams ao vivo são ignorados, e DASH áudio+vídeo é mesclado com o
ffmpeg-staticincluído (nenhum ffmpeg do sistema necessário). - Cookies — Instagram e vídeos restritos por idade geralmente exigem uma sessão logada:
| Variável de ambiente | O que faz | Exemplo |
|---|---|---|
YTDLP_COOKIES | Arquivo de cookies (formato Netscape), vence quando ambos estão definidos | C:/secrets/cookies.txt |
YTDLP_COOKIES_FROM_BROWSER | Extrai cookies de um navegador instalado | chrome, edge, firefox |
A extração de cookies do navegador exige que o navegador esteja fechado no Windows (o banco de dados de cookies fica bloqueado enquanto ele está em execução). Se isso for inconveniente, exporte um
cookies.txtuma vez (ex.: com uma extensão de navegador "Get cookies.txt") e aponteYTDLP_COOKIESpara ele. Vídeos privados/restritos por idade sem cookies válidos não travam a ferramenta — a linhaERROR:do yt-dlp aparece emwarnings[].
TwelveLabs Pegasus (opcional)
Defina a variável de ambiente TWELVELABS_API_KEY para analisar URLs de vídeo diretas com TwelveLabs Pegasus. O Pegasus analisa o vídeo no lado do servidor (visuais e seu próprio áudio) e retorna uma transcrição com carimbo de tempo gerada por IA além de um resumo de IA como texto — capacidades que o DirectAdapter não pode fornecer (uma URL .mp4 bruta não tem transcrição ou resumo por conta própria), e sem necessidade de chave Whisper.
A transcrição é saída de LLM de melhor esforço, não um despejo ASR determinístico: o Pegasus é instruído a emitir linhas [MM:SS] line, e linhas que não correspondem a esse formato são descartadas, então a redação e os carimbos de tempo exatos dependem da adesão do modelo às instruções. Falhas (chave inválida, timeout, erro de API) aparecem no warnings[] da ferramenta em vez de retornar silenciosamente uma transcrição vazia.
A maior vantagem está nos caminhos somente texto: get_transcript e get_metadata retornam uma transcrição e resumo Pegasus para URLs diretas — alguns KB de texto, sem imagens de quadros, sem custo de token por quadro. analyze_video em detail: "standard"/"detailed" ainda extrai quadros adicionalmente (use detail: "brief" para permanecer somente texto).
Vídeos longos: o resumo e a transcrição completa compartilham uma única conclusão limitada (
max_tokens= 16384), então para vídeos muito longos a transcrição pode ser truncada. Para conteúdo de várias horas, dividir por janela de tempo é a abordagem melhor.
É totalmente opt-in e não quebra nada: quando TWELVELABS_API_KEY está definido, o TwelveLabsAdapter lida com URLs de vídeo diretas (ele registra a URL pública com TwelveLabs — sem upload); quando não está definido, o DirectAdapter lida com elas exatamente como antes. URLs do Loom não são afetadas. Obtenha uma chave em playground.twelvelabs.io.
Transcrição (fallback Whisper)
Quando uma fonte não tem transcrição nativa (sem sidecar .vtt/.srt, sem legendas incorporadas, sem legendas de plataforma), a faixa de áudio é transcrita com Whisper via uma cadeia de fallback graciosa (em ordem de execução):
Faixas silenciosas: antes de qualquer execução do Whisper, o áudio é sondado com ffmpeg
volumedetect(primeiros 2 minutos). Uma faixa presente mas muda — comum em Reels/Stories silenciados — pula a transcrição completamente e emite um aviso de que a transcrição vazia é conteúdo esperado, não um erro, economizando uma execução inútil do Whisper.
- @huggingface/transformers (JS-nativo, zero dependências externas) — somente opt-in: esta estratégia é executada primeiro, mas apenas quando
WHISPER_HF_MODELestá explicitamente definido. Quando não está definido (o padrão), a estratégia é completamente ignorada, então o CLI abaixo vence e suas configuraçõesWHISPER_MODEL/WHISPER_LANGUAGEnunca são silenciosamente sobrescritas. - CLI
whisper— usado quando um executávelwhisperé encontrado (pip install -U openai-whisper). AponteWHISPER_BINpara o executável se ele não estiver emPATH. Modelo viaWHISPER_MODEL, idioma viaWHISPER_LANGUAGE. Offmpeg-staticincluído é colocado noPATHdo CLI automaticamente, então nenhum ffmpeg do sistema é necessário. - OpenAI Whisper API — usado quando
OPENAI_API_KEYestá definido.
Nenhum backend configurado? Se nenhum dos três estiver disponível (sem
whisperemPATH/WHISPER_BIN, semOPENAI_API_KEY, semWHISPER_HF_MODEL), as ferramentas de transcrição retornam uma transcrição vazia com um aviso dizendo como habilitar uma — em vez de um "sem transcrição" silencioso. Instaleopenai-whisperou defina uma das chaves acima. (O CLI é iniciado comPYTHONUTF8=1para que transcrições não-inglesas/CJK não travem o processo Python no Windows.)
| Variável de ambiente | Aplica-se a | Padrão | Exemplo |
|---|---|---|---|
WHISPER_MODEL | CLI whisper | tiny | small, medium |
WHISPER_LANGUAGE | CLI whisper / OpenAI API | detecção automática | pt, en, es |
WHISPER_PROMPT | CLI whisper / OpenAI API | — | Doha, Smiles, Livelo, Latam, milheiro |
WHISPER_BIN | CLI whisper | whisper (no PATH) | C:/.../Scripts/whisper.exe |
WHISPER_DEVICE | CLI whisper (enviado apenas se definido) | — | cuda, cpu |
WHISPER_COMPUTE | somente whisper-ctranslate2 | — | float16, int8_float16, int8 |
WHISPER_BEAM_SIZE | CLI whisper (enviado apenas se definido) | — | 5 |
WHISPER_WORD_TIMESTAMPS | CLI whisper (enviado apenas se definido) | desligado | 1 |
WHISPER_HF_MODEL | HF transformers (opt-in) | — (estratégia desligada) | Xenova/whisper-small |
OPENAI_API_KEY | OpenAI API | — | sk-… |
O modelo
tinypadrão é rápido, mas fraco para áudio não-inglês. Para fontes em português (ou outros idiomas não-inglês), instale a CLI e definaWHISPER_MODEL=small(oumedium) +WHISPER_LANGUAGE=ptpara uma precisão muito melhor. AdicioneWHISPER_PROMPTcom um glossário de domínio (nomes de marcas/lugares) para corrigir nomes próprios. Você também pode substituirmodel/language/initialPromptpor chamada emanalyze_video/get_transcript/analyze_videos— sem necessidade de reiniciar.GPU (faster-whisper):
whisper-ctranslate2(pip install -U whisper-ctranslate2) é uma CLI substituta com os mesmos flags, além de--device cuda/--compute_type/--beam_size. AponteWHISPER_BINpara ela e definaWHISPER_DEVICE=cuda(+ opcionalmenteWHISPER_COMPUTE=float16). Esses flags de GPU são controlados por variáveis de ambiente — eles só são passados quando definidos, então oopenai-whispersimples (que rejeita--compute_type) continua funcionando quando eles não estão definidos.Nota para Windows: o pip instala
whisper.exeno diretórioScripts/do Python, que muitas vezes não está noPATHque clientes MCP iniciados por GUI herdam. Se as transcrições voltarem vazias, definaWHISPER_BINpara o caminho completo dewhisper.exe.
Estratégias de Extração de Quadros
A extração de quadros usa uma cadeia de fallback de duas estratégias — nenhuma dependência única é obrigatória:
| Estratégia | Como funciona | Velocidade | Requisitos |
|---|---|---|---|
| yt-dlp + ffmpeg (principal) | Baixa o vídeo, extrai quadros via detecção de cena | Rápida, precisa | yt-dlp (pip install yt-dlp) |
| Navegador (fallback) | Abre o vídeo no Chrome headless, busca nos timestamps, tira screenshots | Mais lenta, sem necessidade de download | Chrome ou Chromium instalado |
O fallback é automático — se o yt-dlp não estiver disponível, o servidor tenta a extração via navegador usando puppeteer-core. Se nenhum estiver disponível, a análise ainda retorna transcrição + metadados + comentários, apenas sem quadros.
Pipeline de Pós-Processamento
Após a extração de quadros, o pipeline aplica automaticamente:
| Etapa | O que faz | Por quê |
|---|---|---|
| Deduplicação de quadros | Remove quadros consecutivos quase idênticos usando hash perceptual (dHash + distância de Hamming) | Gravações de tela costumam ter longos momentos estáticos — a deduplicação remove quadros redundantes, economizando tokens |
| OCR | Extrai texto visível na tela de cada quadro (via tesseract.js). Cada quadro é primeiro pré-processado — escala de cinza + upscale 2× + normalização de contraste + nitidez — o que melhora materialmente a precisão em sobreposições estilizadas (preços, datas, cupons, CTAs). | Captura código, mensagens de erro, saída de terminal, texto de interface que a transcrição não cobre |
| Linha do tempo anotada | Mescla timestamps da transcrição + timestamps dos quadros + texto OCR em uma única visão cronológica | Dá à IA uma visão unificada de "o que foi dito, o que mudou visualmente e que texto apareceu" em cada momento |
A etapa de OCR requer tesseract.js (incluído como dependência). Se falhar ao carregar, a análise continua sem OCR — nenhum quadro ou transcrição é perdido. O pré-processamento de OCR está ativado por padrão; defina MCP_OCR_PREPROCESS=0 para aplicar OCR nos quadros brutos.
O OCR sempre lê o quadro em resolução total, não a cópia enviada ao cliente. Os dois têm funções diferentes: o quadro enviado é limitado para custo de tokens, enquanto o reconhecimento precisa de cada pixel que puder obter.
Tamanho do quadro (capturas de UI densas)
Os quadros enviados são limitados a 800 px de largura, o que atende ao caso comum — clipes com pessoa falando, Reels, reprodução de bugs — onde o assunto preenche o quadro.
É o tamanho errado para uma captura de UI densa: uma gravação de terminal, dashboard, IDE ou planilha, onde o significado está em texto pequeno. Uma gravação de tela 1920×1080 sem redimensionamento chega a 800×450, e uma fonte de UI de 15 px cai abaixo do que um modelo de visão consegue resolver.
Passe maxWidth por chamada para manter mais (ou toda) a resolução da fonte — 0 desativa o limite:
get_frames(url, { maxFrames: 8, maxWidth: 0 }) // source resolution
get_frame_at(url, "2:14", { maxWidth: 1920 })
analyze_video(url, { detail: "standard", maxWidth: 1568 })
Suportado em analyze_video, analyze_videos, analyze_moment, get_frames, get_frame_at e get_frame_burst, e na CLI como --max-width <px>.
Quadros nativos custam várias vezes mais contexto do que o padrão, então aumente o limite deliberadamente — get_frames retorna até 20 quadros e analyze_video em detailed até 60.
| Variável | Aplica-se a | Padrão | Notas |
|---|---|---|---|
MCP_FRAME_MAX_WIDTH | Largura do quadro enviado, em px | 800 | 0 (ou native/full/original) desativa o limite. Um maxWidth por chamada tem precedência sobre ele |
MCP_FRAME_JPEG_QUALITY | Qualidade JPEG do quadro enviado | 70 | Aumente quando glifos finos importarem; apenas por variável de ambiente, não há parâmetro de qualidade por chamada. Valores fora de 1–100 caem para o padrão |
MCP_CACHE_DIR | Raiz para o cache do tessdata e o --out padrão da CLI | diretório de cache por usuário | Apenas caminhos absolutos (um valor relativo é ignorado). Use quando $HOME for somente leitura ou ausente — um contêiner endurecido, ProtectHome=, um home com cota. A imagem Docker publicada define isso como /tmp/mcp-video-analyzer-cache para que --read-only --tmpfs /tmp funcione de imediato |
Um valor que qualquer variável não possa usar — 1e3, 1920px, uma qualidade de 150 — é rejeitado com um aviso único no stderr e o padrão é aplicado. Não é aceito silenciosamente: o objetivo do ajuste é escapar de um downscale que, de outra forma, parece um resultado normal.
Prefira o parâmetro por chamada: o servidor inicia uma vez por sessão, então uma variável de ambiente não pode diferir entre uma visão geral de um clipe do YouTube e uma leitura detalhada de uma gravação de tela. A largura que uma chamada realmente usa faz parte da chave de cache e sidecar, então analisar o mesmo vídeo a 800 px e depois a maxWidth: 0 reexecuta o pipeline em vez de retornar o primeiro resultado duas vezes.
Ferramentas Complementares
Chrome DevTools MCP
Para depuração web ao vivo junto com a análise de vídeo, combine este servidor com o Chrome DevTools MCP:
claude mcp add chrome-devtools npx @anthropic-ai/mcp-devtools@latest
Quando usar cada um:
| Cenário | Ferramenta |
|---|---|
| Relatório de bug gravado como vídeo Loom | mcp-video-analyzer — extrai transcrição, quadros e texto de erro da gravação |
| Depuração ao vivo de uma página web | Chrome DevTools MCP — inspeciona DOM, console, rede, tira screenshots |
| Vídeo mostra problema de UI, precisa reproduzi-lo | Use ambos: analise o vídeo primeiro, depois abra a página no Chrome DevTools para reproduzir |
Os dois MCPs se complementam: o analisador de vídeo entende conteúdo gravado, o DevTools interage com páginas ao vivo.
Exemplo de Saída
A pasta examples/loom-demo/ contém saídas reais da análise de um vídeo Loom público (Boost In-App Demo Video, 2:55).
| Arquivo | O que mostra |
|---|---|
metadata.json | Título, duração, plataforma |
transcript.json | 42 entradas com timestamps e IDs de falante |
timeline.json | Visão cronológica unificada (transcrição + quadros mesclados) |
moment-transcript-0m30s-0m45s.json | Transcrição filtrada para analyze_moment (0:30–0:45) |
full-analysis.json | Saída completa de analyze_video |
Imagens dos quadros (19 no total em examples/loom-demo/frames/):
scene_*.jpg— detecção de mudança de cena (transições visuais principais)dense_*.jpg— amostragem densa a 1fps (a cada 10º quadro salvo como amostra)burst_*.jpg— extração em rajada para análise de momento (0:30–0:45)
Regenerar após alterações:
npx tsx examples/generate.ts— requer yt-dlp + acesso à rede.
Desenvolvimento
# Install dependencies
npm install
# Run all checks (format, lint, typecheck, knip, tests)
npm run check
# Audit dependencies. `security` covers what the published package ships and
# is a blocking CI job; `security:all` adds devDependencies. Both also run on
# a weekly cron, because npm audit reads a live advisory database.
npm run security
# Build
npm run build
# Run E2E tests (requires network; add WHISPER_E2E=1 to include the
# transcription outcome test — needs a whisper CLI installed)
npm run test:e2e
# Just the video-format matrix: a real clip per container/codec
# (mp4/h264+hevc+av1, webm, mkv, mov, avi, m4v, mpeg, mpg, m2ts, mts,
# 3gp, ogv, flv, wmv) decoded end to end. ~15s on a warm cache; the
# first run fetches ~7MB of tesseract traineddata.
npm run test:formats
# Build + boot the real MCP server/CLI (seconds)
npm run test:smoke
# Everything: check → e2e → smoke → verify-package
npm run verify-all
# Open MCP Inspector for manual testing
npm run inspect
Arquitetura
src/
├── index.ts # Entry point (shebang + stdio)
├── server.ts # FastMCP server + tool registration
├── tools/ # MCP tool definitions (7 tools)
│ ├── analyze-video.ts # Full analysis with detail levels + caching
│ ├── analyze-moment.ts # Deep-dive on a time range
│ ├── get-transcript.ts # Transcript-only with Whisper fallback
│ ├── get-metadata.ts # Metadata + comments + chapters
│ ├── get-frames.ts # Frames-only (scene-change or dense)
│ ├── get-frame-at.ts # Single frame at timestamp
│ └── get-frame-burst.ts # N frames in a time range
├── adapters/ # Source-specific logic
│ ├── adapter.interface.ts # IVideoAdapter interface + registry
│ ├── loom.adapter.ts # Loom: authless GraphQL
│ ├── local-file.adapter.ts # Local files: absolute path or file:// URI
│ ├── twelvelabs.adapter.ts # TwelveLabs Pegasus: transcript + AI summary (opt-in)
│ └── direct.adapter.ts # Direct URL: any mp4/webm link
├── processors/ # Shared processing
│ ├── frame-extractor.ts # ffmpeg scene detection + dense + burst extraction
│ ├── browser-frame-extractor.ts # Headless Chrome fallback for frames
│ ├── audio-transcriber.ts # Whisper fallback (HF transformers → CLI → OpenAI)
│ ├── image-optimizer.ts # sharp resize/compress
│ ├── frame-dedup.ts # Perceptual dedup (dHash + Hamming distance)
│ ├── frame-ocr.ts # OCR text extraction (tesseract.js)
│ └── annotated-timeline.ts # Unified timeline (transcript + frames + OCR)
├── config/
│ └── detail-levels.ts # brief / standard / detailed config
├── utils/
│ ├── cache.ts # In-memory TTL cache with LRU eviction
│ ├── field-filter.ts # Selective field filtering for responses
│ ├── url-detector.ts # Platform detection from URL
│ ├── vtt-parser.ts # WebVTT → transcript entries
│ └── temp-files.ts # Temp directory management
└── types.ts # Shared TypeScript interfaces
Licença
MIT