seo-tools-mcp
Cinco servidores MCP somente leitura para SEO no mercado Google/Yandex (RU/CIS): SERP (XMLStock), Yandex Wordstat, Google Search Console, Yandex.Webmaster, Yandex.Metrica.
Documentação
seo-tools-mcp
Русский | English
Oito servidores MCP stdio universais para SEO: acesso a SERP, Wordstat, Google Search Console, Google Analytics 4, Yandex.Webmaster, Yandex.Metrica e A-Parser self-hosted diretamente do Claude Code (e de qualquer cliente MCP). Todas as ferramentas são read-only — nada é publicado ou alterado nas suas contas, a saída é JSON estrito. Isso é declarado de forma legível por máquina pela anotação readOnlyHint; ela está deliberadamente ausente em vinte ferramentas, cada chamada das quais consome um recurso pago (requisição ao XMLStock/XMLRiver, tráfego de proxy do A-Parser) — caso contrário, o cliente as consideraria inofensivas e pararia de pedir confirmação antes de executar em um grande pool. Não são vinculadas a um site específico: os padrões (propriedade GSC, propriedade GA4, host do Webmaster, contador da Metrica) são configurados em tempo real.
🛰 Usamos esses servidores em produção no PBN Workers — infraestrutura de topo de busca: semântica, PBN e satélites, automação de SEO. Precisa de tráfego orgânico estável — venha.
| Servidor | Ferramentas de trabalho | Autenticação |
|---|---|---|
xmlstock | xmlstock_serp, xmlstock_images, xmlstock_news, xmlstock_video, xmlstock_wordstat, xmlstock_wordstat_dynamics, xmlstock_wordstat_regions, xmlstock_wordstat_regions_tree, xmlstock_balance | Chave de API |
xmlriver | xmlriver_serp, xmlriver_images, xmlriver_news, xmlriver_maps, xmlriver_check_index, xmlriver_suggest, xmlriver_related_questions, xmlriver_balance | Chave de API |
wordstat | wordstat_frequency, wordstat_dynamics, wordstat_regions, wordstat_regions_tree | Api-Key Yandex Cloud |
gsc | gsc_query, gsc_inspect_url, gsc_list_sites, gsc_get_site, gsc_list_sitemaps, gsc_get_sitemap | OAuth (todas as propriedades da conta) / service account |
ga4 | ga4_list_properties, ga4_property_details, ga4_metadata, ga4_check_compatibility, ga4_report, ga4_bytime, ga4_traffic_sources, ga4_geo, ga4_devices, ga4_top_pages, ga4_events, ga4_funnel, ga4_annotations, ga4_realtime | OAuth (todas as propriedades da conta) / service account |
ywm | ywm_hosts, ywm_summary, ywm_search_queries, ywm_queries_history, ywm_recommended_queries, ywm_popular, ywm_indexing_history, ywm_sqi_history, ywm_external_links, ywm_broken_links, ywm_diagnostics, ywm_important_urls, ywm_sitemaps | OAuth (auto-refresh) |
metrika | metrika_report, metrika_bytime, metrika_counters, metrika_goals, metrika_traffic_sources, metrika_geo, metrika_devices, metrika_landing_behavior, metrika_search_phrases, metrika_top_landings | OAuth (auto-refresh) |
aparser | aparser_ping, aparser_status, aparser_proxies, aparser_parsers, aparser_parser_fields, aparser_get_preset, aparser_serp_google, aparser_serp_yandex, aparser_suggest, aparser_request, aparser_bulk_request | A-Parser self-hosted (URL + senha da API) |
Onde está publicado: npm (oito pacotes), MCP Registry oficial, GitHub MCP Registry (todos os oito servidores), marketplace de plugins do Claude Code (veja abaixo) e bundles .mcpb nos releases.
Cada servidor também possui ferramentas de autenticação <server>_auth_status e <server>_set_credentials (veja Autorização interativa).
Ferramentas por serviço
xmlstock — SERP Google/Yandex
xmlstock_serp— resultados web do Google/Yandex (orgânicos + destaques + recursos de SERP): região, dispositivo, safe search, ordenação (Yandex), período, blocos de anúncios; terceiro motoryandex_xml— Yandex XML oficial (groupby até 100 por 1 requisição, hlword em qualquer dispositivo, estatísticas found/found-docs; tarifa a partir de 24 ₽/1000)xmlstock_images— busca de imagens do Google (url da página + url da imagem + título)xmlstock_news— notícias do Google (título, fonte, data, snippet)xmlstock_video— vídeos do Google (url, título, prévia, host, canal, duração)xmlstock_wordstat— Yandex Wordstat: topo + consultas semelhantes com frequência (possível por região), operadores do Wordstatxmlstock_wordstat_dynamics— dinâmica de frequência ao longo do tempo (dia/semana/mês)xmlstock_wordstat_regions— demanda por regiões (count, share, affinity index + nomes das regiões)xmlstock_wordstat_regions_tree— árvore de regiões do Wordstat (id + nome + caminho)xmlstock_balance— saldo da conta / verificação de chave (grátis)
Wordstat via XMLStock — com a mesma chave
XMLSTOCK_*do SERP; não precisa de Yandex Cloud (diferente do servidor separadowordstat).
xmlriver — SERP Google/Yandex + verificação de indexação
xmlriver_serp— orgânicos do Google/Yandex (profundidade obtida por paginação: cada 10 posições = 1 requisição paga), flag de presença de AI Overview; opçãoincludeAIOverview— texto completo do Resumo de IA + links citados (pagoai=1, apenas Google);includeAdditional— blocos SERP adicionais do Google de<addresults>(knowledge_graph, localresultsplace, rs e outros; o conteúdo depende das opções pagas do painel do XMLRiver, blocos não recebidos — emadditional.unavailable); geo-targeting do Google —location(cidade →loc, «Moscow»/«1011969») ecountry(ISO/id numérico, inferido automaticamente da cidade);device— desktop/mobile/tablet,os(ios/android) enviado apenas comdevice=mobilexmlriver_images— imagens do Google (página + url da imagem + título + fonte + dimensões); geo —location/countryxmlriver_news— notícias do Google (título, fonte, data, snippet), filtro por tempo; geo —location/countryxmlriver_maps— busca de estabelecimentos no Google Maps (setab=maps, obrigatórioszoom1–15 ecoords«latitude,longitude»,count5–50): nome, avaliação, endereço, telefone, serviços, coordenadas, place_id, número de avaliações. IMPORTANTE: formato conforme a documentação, não confirmado ao vivo (no conta de teste o endpoint responde consistentemente com código 500 — provavelmente é necessária uma opção paga do painel)xmlriver_check_index— verificação de indexação de URL no Google/Yandex (inindex)xmlriver_suggest— sugestões de busca do Google (até 50 frases por chamada, pago por cada frase); geo das sugestões —location/countryxmlriver_related_questions— bloco «Perguntas relacionadas» / People Also Ask do Google (perguntas sempre; respostas — apenas com a opção paga «Related Questions com respostas» ativada no painel)xmlriver_balance— saldo da conta / verificação de chave (grátis)
wordstat — frequências do Yandex
wordstat_frequency— frequência ampla e exata, consultas de refinamento (related) e associaçõeswordstat_dynamics— frequência ao longo do tempo (dia/semana/mês)wordstat_regions— distribuição por regiões com índice de afinidade e nomes das regiõeswordstat_regions_tree— árvore completa de regiões do Wordstat (id + nome)
gsc — Google Search Console
gsc_query— Search Analytics (cliques/impressões/CTR/posição), auto-paginação,dataStatefinal/all, filtros arbitrários de dimensões (filters, semântica AND) eaggregationType(auto/byProperty/byPage)gsc_inspect_url— URL Inspection: status de indexação, cobertura, canonical, último rastreamento, mobile usability, rich resultsgsc_list_sites— propriedades disponíveis para a autorizaçãogsc_get_site— nível de acesso à propriedadegsc_list_sitemaps— sitemaps enviados com statusgsc_get_sitemap— detalhes de um sitemap
Datas do Search Analytics — no fuso Pacific Time (não MSK); histórico de ~16 meses; dados finais atrasam ~2-3 dias (recentes — dataState=all); ctr na resposta — proporção 0..1.
ga4 — Google Analytics 4
ga4_list_properties— propriedades GA4 disponíveis para a autorização (daqui vem opropertyId— não é o Measurement IDG-XXXXXXX)ga4_metadata— quais dimensões e métricas estão disponíveis NESTA propriedade, incluindo personalizadas (customEvent:…); busca por substring,blockedReasons(por essa métrica o relatório retornará zeros) etype(inteiro/decimal parametricFilters)ga4_check_compatibility— se a combinação de dimensões/métricas é compatível nesta propriedade, sem relatório pesado; se incompatível — quais campos removerga4_report— relatório arbitrário: quaisquer dimensões × métricas, filtros por dimensões, ordenação (Data API completorunReport)ga4_bytime— dinâmica de métricas ao longo do tempo (dia/hora/semana/mês)ga4_traffic_sources— fontes de tráfego: grupo de canais, source/medium, campanha;organicOnly— apenas orgânicoga4_geo— país/região/cidadega4_devices— tipo de dispositivo/SO/navegadorga4_top_pages— top de páginas porpagePath, página de entrada ou título; filtrosorganicOnlyepathContainsga4_events— eventos poreventName;keyEventsOnly— apenas eventos-chave (antigas conversões)ga4_realtime— relatório em tempo real (últimos 30 minutos)ga4_funnel— funil (runFunnelReport): quantos chegaram a cada etapa e onde desistiram; etapa = evento e/ou condições por dimensões, detalhamento por dimensão. Dentro das etapas vale o esquema da Exploration API (pagePathindisponível lá), a cota é separada e a consulta é mais cara que um relatório comumga4_annotations— anotações da propriedade: marcações em datas, incluindo as criadas pela própria GA4 (systemGenerated) — explicação frequente para um salto inexplicável na dinâmicaga4_property_details— cartão da propriedade: fuso horário dos relatórios, moeda, nível de serviço (STANDARD/360) e fluxos de dados com seus Measurement IDG-XXXXXXX
Em todas as ferramentas de relatório há includeQuota — quantos «tokens» do Data API a consulta consumiu e quantos restam por hora/dia.
Unidades e datas: bounceRate/engagementRate o GA4 retorna como proporção 0..1 (não porcentagens); as datas são calculadas no fuso horário da propriedade — aceita YYYY-MM-DD e palavras-chave do GA4 (today, yesterday, 28daysAgo), o fuso real é retornado na resposta. Nas respostas há totalRows/truncated, e thresholded: true significa que parte dos dados está oculta pelo limite de confidencialidade do GA4.
ywm — Yandex.Webmaster
ywm_hosts— id do usuário + sites confirmadosywm_summary— IKS, páginas na busca, excluídas, problemas do site por importânciaywm_search_queries— análise de consultas por URL (~2 semanas por padrão; sobrescrito por dateFrom/dateTo)ywm_queries_history— impressões/cliques/posições totais ao longo do tempoywm_recommended_queries— consultas recomendadas aproximadas (demanda + déficit de cliques)ywm_popular— consultas populares do hostywm_indexing_history— páginas na busca ao longo do tempoywm_sqi_history— IKS ao longo do tempoywm_external_links— amostra de links externos + número totalywm_broken_links— links internos/externos quebradosywm_diagnostics— problemas do siteywm_important_urls— URLs monitoradas com status de indexação/buscaywm_sitemaps— sitemaps com status
metrika — Yandex.Metrica
metrika_report— relatório arbitrário: quaisquer dimensions × metrics, filtros, ordenação (Stat API completo)metrika_bytime— métricas ao longo do tempo (dia/semana/mês/hora)metrika_traffic_sources— visitas/usuários/rejeições por fontes de tráfegometrika_geo— visitas por país/região/cidademetrika_devices— visitas por dispositivo/SO/navegadormetrika_goals— lista de metas (conversões)metrika_counters— contadores disponíveismetrika_landing_behavior— comportamento nas páginas de destino + alcance de metasmetrika_search_phrases— frases de busca (orgânico)metrika_top_landings— top de páginas de destino orgânicas
aparser — ponte para o A-Parser self-hosted
aparser_ping— verificação de conexão com a instância e senha da APIaparser_status— veredito de prontidão: versão, parsers instalados, fila, proxies vivosaparser_proxies— proxies vivos da instância (pode ser em lotes de proxy checkers; credenciais de proxy não são exibidas)aparser_parsers— parsers instalados na instânciaaparser_parser_fields— campos de resultado que o parser consegue retornar (flat + arrays)aparser_get_preset— opções do preset de config do parser (valores sensíveis são mascarados)aparser_serp_google— orgânico do Google (parserSE::Google); proxy padrão + preflight de proxies vivosaparser_serp_yandex— orgânico do Yandex (SE::Yandex); região vialraparser_suggest— sugestões de busca do Google/Yandexaparser_request— requisição síncrona universal para qualquer parser (oneRequest)aparser_bulk_request— requisição em lote: um parser, muitas requisições em N threads (bulkRequest)
É necessário ter sua própria instância em execução do A-Parser (licença + servidor): a ponte gerencia, mas não hospeda nem faz proxy para ela. Proxies e proxy checkers (lotes) são configurados uma vez na GUI do A-Parser — a ponte os lê, verifica (preflight) e seleciona (
checkers), mas não os cria. v1 é síncrono e somente leitura: fila de tarefas e grandes exportações assíncronas não estão conectadas.
Início rápido
Opção 1 — com um clique para Claude Desktop (.mcpb)
A forma mais simples, sem precisar instalar nada manualmente: baixe o .mcpb desejado na página de releases e abra com duplo clique — o Claude Desktop instalará o servidor sozinho e pedirá as chaves no diálogo de instalação.
- Servidores com chave de API (
xmlstock,xmlriver,wordstat,aparser) — as chaves são inseridas diretamente no instalador. - Servidores com OAuth (
gsc,ga4,ywm,metrika) não pedem nada: a autorização acontece no chat (<server>_oauth_start→<server>_oauth_finish).
Os bundles são autossuficientes (~0,2 MB, dependências inclusas); Node.js 20+ é necessário apenas para a opção com npx. Para compilar você mesmo: pnpm build:mcpb.
Opção 2 — plugin para Claude Code (marketplace)
Equivalente ao .mcpb, mas para Claude Code: servidor, chaves e dicas são instalados com um único comando, as chaves são solicitadas via diálogo e os segredos vão para o armazenamento do sistema, não para um arquivo aberto.
claude plugin marketplace add antohins/seo-tools-mcp
Em seguida — apenas as fontes necessárias; cada plugin puxa exatamente um servidor:
claude plugin install xmlstock@seo-tools-mcp
claude plugin install gsc@seo-tools-mcp
claude plugin install ga4@seo-tools-mcp
Estão disponíveis xmlstock, xmlriver, wordstat, gsc, ga4, ywm, metrika, aparser — e o seo-tools, que instala todos os oito de uma vez. O bundle é conveniente, mas são ~100 ferramentas em cada sessão: se você trabalha apenas com Webmaster e Metrica, instale dois plugins em vez do bundle.
As chaves podem ser inseridas imediatamente (--config KEY=VALUE) ou depois via /plugin configure <плагин>@seo-tools-mcp:
claude plugin install xmlstock@seo-tools-mcp --config XMLSTOCK_USER=12345 --config XMLSTOCK_KEY=...
Campos marcados como secretos (chaves de API, segredos OAuth) são colocados pelo Claude Code no armazenamento do sistema; eles não aparecem no settings.json. Plugins com OAuth (gsc, ga4, ywm, metrika) pedem apenas client_id/secret na instalação — o login em si acontece no chat via <сервер>_oauth_start → <сервер>_oauth_finish.
Junto com o servidor, o plugin traz habilidades — instruções procedurais sobre sua fonte:
como não queimar o saldo ao coletar posições, por que o freq_broad infla o tráfego várias vezes, por que
o GA4 retorna zeros silenciosamente, como a posição média do GSC difere da coletada na busca. No contexto,
elas ocupam sempre ~110 tokens por habilidade e são expandidas apenas quando realmente necessárias.
Opção 3 — via npx (sem clonagem)
Cada servidor é um pacote npm autossuficiente seo-tools-mcp-<сервер>; instala-se com um único comando:
claude mcp add xmlstock --scope user -- npx -y seo-tools-mcp-xmlstock
claude mcp add xmlriver --scope user -- npx -y seo-tools-mcp-xmlriver
claude mcp add wordstat --scope user -- npx -y seo-tools-mcp-wordstat
claude mcp add gsc --scope user -- npx -y seo-tools-mcp-gsc
claude mcp add ga4 --scope user -- npx -y seo-tools-mcp-ga4
claude mcp add ywm --scope user -- npx -y seo-tools-mcp-ywm
claude mcp add metrika --scope user -- npx -y seo-tools-mcp-metrika
claude mcp add aparser --scope user -- npx -y seo-tools-mcp-aparser
Precisa de apenas um servidor?
Os servidores não são interligados: pegue um único pacote e ignore os demais. Cada um é autossuficiente — o código comum @seo-tools/shared está embutido no build, então não há dependências extras nem "cauda" do monorepo. Basta instalar o pacote desejado do npm — já vem tudo pronto (npx -y baixa e executa automaticamente):
| Pacote (npm) | Servidor |
|---|---|
seo-tools-mcp-xmlstock | SERP Google/Yandex + Wordstat |
seo-tools-mcp-xmlriver | SERP Google/Yandex + verificação de indexação |
seo-tools-mcp-wordstat | frequências do Yandex (Yandex Cloud) |
seo-tools-mcp-gsc | Google Search Console |
seo-tools-mcp-ga4 | Google Analytics 4 |
seo-tools-mcp-ywm | Yandex.Webmaster |
seo-tools-mcp-metrika | Yandex.Metrica |
seo-tools-mcp-aparser | ponte para o A-Parser self-hosted |
# добавить один сервер в Claude Code
claude mcp add xmlstock --scope user -- npx -y seo-tools-mcp-xmlstock
# или запустить напрямую (ключи через env)
XMLSTOCK_USER=... XMLSTOCK_KEY=... npx -y seo-tools-mcp-xmlstock
Em qualquer cliente MCP (Claude Desktop, Cursor…) — basta adicionar um bloco no mcpServers:
{
"mcpServers": {
"xmlstock": {
"command": "npx",
"args": ["-y", "seo-tools-mcp-xmlstock"],
"env": { "XMLSTOCK_USER": "...", "XMLSTOCK_KEY": "..." }
}
}
}
Instalação direta de um único pacote via link do GitHub (
npm i github:antohins/seo-tools-mcp) não é suportada: é um monorepo pnpm, um subpacote separado não pode ser instalado assim. Para instalar a partir do código-fonte — opção B abaixo (clonar + compilar). Os pacotes prontos estão no npm.
Opção 4 — a partir do código-fonte
git clone https://github.com/antohins/seo-tools-mcp.git && cd seo-tools-mcp
pnpm install && pnpm build
ROOT=$(pwd)
for s in xmlstock xmlriver wordstat gsc ga4 ywm metrika aparser; do
claude mcp add "$s" --scope user -- node "$ROOT/servers/$s/dist/index.js"
done
Em seguida (qualquer opção) — direto no diálogo do Claude Code: "configure acesso ao xmlstock" → o agente chamará xmlstock_auth_status, indicará quais chaves são necessárias e onde obtê-las, receberá via xmlstock_set_credentials e salvará. Depois disso, faça perguntas em linguagem natural: "colete o top-10 do Yandex para a consulta X", "frequência das frases …", "cliques/impressões do GSC no último mês". Chaves e OAuth são configurados uma única vez (veja Obtendo acessos).
Autorização interativa (em qualquer sessão)
Cada servidor possui ferramentas de auth — as chaves podem ser fornecidas diretamente no diálogo, sem editar arquivos ou reiniciar:
<server>_auth_status— chamado no início do trabalho: mostra quais chaves estão definidas (mascaradas), quais faltam e como obtê-las (etapas de registro).<server>_set_credentials— salva os valores fornecidos no~/.config/seo-tools-mcp/.env(permissões 600) e aplica imediatamente.gsc_save_sa_json— aceita o conteúdo do JSON da chave da conta de serviço, coloca-o no diretório de config e retorna o email que precisa ser adicionado ao GSC.ywm_oauth_start/metrika_oauth_start→ link de autorização do Yandex; o usuário abre, permite, copia o código →*_oauth_finishtroca o código por tokens access+refresh. Depois disso, o token é renovado automaticamente ao expirar (code flow, não implicit).
Cenário típico de nova sessão: "configure acesso ao xmlstock" → o agente chama xmlstock_auth_status → solicita as chaves ausentes → xmlstock_set_credentials → trabalha.
⚠ Chaves fornecidas pelo chat passam pelo contexto do modelo. Para máxima higiene, você ainda pode inseri-las manualmente no ~/.config/seo-tools-mcp/.env — os servidores carregam o arquivo sozinhos.
Multi-conta
Os sites dos clientes estão distribuídos em diferentes contas Google/Yandex — perfis nomeados são suportados:
- Cada ferramenta de trabalho aceita um parâmetro opcional
account("clientX", "agency"...). Sem ele, o perfil principal é usado — compatibilidade total com versões anteriores. - As chaves do perfil ficam no mesmo config com sufixo:
GSC_REFRESH_TOKEN__clientX,YANDEX_OAUTH_TOKEN__clientX,XMLSTOCK_KEY__clientX… - Adicionar perfil:
gsc_oauth_start(account="clientX")→ o usuário autoriza com uma conta Google diferente →gsc_oauth_finish(account="clientX"). Analogamente,ywm_oauth_start/finish(account=...)para Yandex; chaves de API —<server>_set_credentials(account="clientX", ...). - Os apps OAuth são compartilhados: um único Google-client e um único app Yandex atendem todos os perfis (o cliente é criado uma vez, autorizações — quantas forem necessárias). Apenas tokens são armazenados por conta; o refresh renova o token do próprio perfil.
- Resolução estrita:
account="clientX"sem chaves configuradas → erro com a lista de perfis configurados (sem fallbacks silenciosos para outra conta). Os padrões (GSC_SITE_URL__clientX,YWM_HOST_ID__clientX,METRIKA_COUNTER_ID__clientX) também são por conta. <server>_auth_statusmostra todos os perfis e suas chaves (mascaradas).- Alternativa para isolamento rígido: arquivo env separado via
SEO_TOOLS_MCP_ENV(com caminho definido, o config doméstico NÃO é lido).
Instalação
cd seo-tools-mcp
pnpm install
pnpm build
Segredos
Arquivo env único: ~/.config/seo-tools-mcp/.env (permissões 600). Todos os servidores o leem na inicialização, e *_set_credentials/*_oauth_finish gravam nele automaticamente — edição manual não é obrigatória. Modelo — .env.example. Variáveis do ambiente do processo têm prioridade sobre o arquivo. Caminho alternativo para o arquivo — SEO_TOOLS_MCP_ENV (assim um host pode manter vários perfis independentes: diferentes claude mcp add com diferentes SEO_TOOLS_MCP_ENV).
Registro no Claude Code
ROOT=/path/to/seo-tools-mcp
claude mcp add xmlstock --scope user -- node $ROOT/servers/xmlstock/dist/index.js
claude mcp add wordstat --scope user -- node $ROOT/servers/wordstat/dist/index.js
claude mcp add gsc --scope user -- node $ROOT/servers/gsc/dist/index.js
claude mcp add ga4 --scope user -- node $ROOT/servers/ga4/dist/index.js
claude mcp add ywm --scope user -- node $ROOT/servers/ywm/dist/index.js
claude mcp add metrika --scope user -- node $ROOT/servers/metrika/dist/index.js
--scope user — disponível em todas as sessões/projetos. Para compartilhar com a equipe — --scope project (criará .mcp.json no repositório; segredos devem ser inseridos apenas via ${VAR}).
Obtendo acessos (por serviço)
Tudo nesta seção está duplicado nas respostas do
<server>_auth_status— o agente indicará os passos sozinho. Abaixo — para leitura humana.
XMLStock (prioridade 1) — SERP Google + Yandex
- Registro: https://xmlstock.com → painel pessoal, adicione saldo (Google XML e Yandex Live — a partir de 12 ₽/1000 requisições).
- Pegue o ID do usuário e a chave de API →
XMLSTOCK_USER,XMLSTOCK_KEY(ou viaxmlstock_set_credentials). - Verificação:
xmlstock_balance.
Nuances (descobertas em respostas reais):
- destaques da busca (
text_bolds) — parâmetrohlword=1, tag<hlword>no XML aninhado (parseado via stopNodes, palavras vizinhas são unidas em frases); PAA e related searches —related=1(PAA apenas no Google); - a busca mobile não retorna hlword/PAA/related — o snapshot mobile traz apenas posições+snippets; destaques devem ser coletados no desktop;
- páginas com 0 em ambos os mecanismos; orgânico por página pode ser <10 — o servidor completa com mais uma página (+1 requisição paga);
lraceita IDs de regiões do Yandex para ambos os mecanismos (XMLStock mapeia para o Google automaticamente);- erros HTTP 200 +
<error code>: 20–25/101/110/111/500 são repetidos, 55 — rate-limit com pausa, 15 = resultado vazio (dinheiro debitado), 31/42 — fatais (autorização); - XMLStock NÃO tem Wordstat — frequências via servidor separado (API oficial do Wordstat do Yandex).
Wordstat (prioridade 1) — frequências do Yandex
Wordstat API v2 oficial (parte do Yandex Cloud Search API) — gratuito, sem solicitações nem OAuth. Uma vez no https://console.yandex.cloud:
- Crie um diretório (folder) ou use um existente → o ID dele no
WORDSTAT_FOLDER_ID. - Crie uma conta de serviço com o papel
search-api.webSearch.user. - Emita para ela uma chave de API com escopo
yc.search-api.execute→WORDSTAT_API_KEY. - Verificação:
wordstat_frequencycom qualquer frase.
Nuances: frequência exata = operadores "!слово !слово" (suportados em topRequests/regions; em dynamics — apenas com period=daily); dados de topRequests — dos últimos 30 dias; count chega como strings (parseado); cotas 10 rps / 100 requisições por hora (429 é repetido, mas para coleta em massa planeje throttling); associations no máximo 20.
Google Search Console (prioridade 1)
Dois caminhos; o recomendado — OAuth: o token herda o acesso da sua conta Google e vê todas as propriedades GSC dela de uma vez (incluindo futuras), sem precisar adicionar usuário em cada propriedade.
Caminho A — OAuth (uma vez):
- https://console.cloud.google.com → projeto → APIs & Services → Library → ativar Google Search Console API.
- OAuth consent screen: tipo External; inclua você em Test users. (Para refresh-token durar mais de 7 dias — clique em Publish app; o aviso "unverified" na autorização é normal para uso pessoal.)
- Credentials → Create credentials → OAuth client ID → Desktop app → pegue o client ID + secret.
- No chat:
gsc_oauth_start(informe clientId+secret) → abra o link → permita → o navegador redirecionará paralocalhost:8585, o código será capturado automaticamente →gsc_oauth_finish. - Verificação:
gsc_list_sites— mostrará todas as propriedades da conta. Caminho B — conta de serviço (para cron headless): IAM → Service Accounts → chave JSON →gsc_save_sa_json(ou caminho emGSC_SA_JSON) → adicionar o e-mail da conta em cada propriedade necessária do GSC (Configurações → Usuários e permissões, "Total").
Se ambos forem definidos — OAuth tem prioridade.
Google Analytics 4 (prioridade 1)
A autorização é a mesma do GSC, e o aplicativo OAuth é compartilhado (GOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRET são reutilizados). Mas o escopo do GA4 é próprio, então é necessária uma autorização separada — uma única vez.
- No mesmo projeto console.cloud.google.com → APIs & Services → Library → ativar Google Analytics Data API e Google Analytics Admin API.
- No chat:
ga4_oauth_start(se client ID/secret já estiverem salvos para GSC — sem argumentos) → abrir o link → permitir → o navegador redireciona paralocalhost:8586(a porta difere do GSC, para os servidores não conflitarem), o código é capturado automaticamente →ga4_oauth_finish. - Verificação:
ga4_list_properties— mostrará todas as propriedades da conta e seuspropertyId. - É conveniente salvar a propriedade padrão:
ga4_set_credentials→GA4_PROPERTY_ID(id numérico do item 3), caso contrário, passarpropertyIdem cada chamada.
Caminho B — conta de serviço: chave JSON → ga4_save_sa_json → adicionar o e-mail da conta na propriedade GA4 (Administrador → Gerenciamento de acesso ao recurso, função "Visualização").
Yandex OAuth (Webmaster + Metrica — um aplicativo, um token)
- Uma única vez: https://oauth.yandex.ru/client/new → "Serviços web", Redirect URI:
https://oauth.yandex.ru/verification_code. Permissões (escopo): Yandex.Webmaster — "Obter informações sobre sites" (webmaster:hostinfo) + "Gerenciar sites" (webmaster:verify); Yandex.Metrica — "Obter estatísticas" (metrika:read). Pegar ClientID e Client secret. - Depois — interativamente no chat:
ywm_oauth_start(passar ClientID + secret, serão salvos) → abrir o link na conta proprietária do site/contador → copiar o código →ywm_oauth_finish. Serão obtidos tokens access+refresh, compartilhados entre ywm e metrika; são atualizados automaticamente. - Padrões:
YWM_HOST_ID(lista —ywm_hosts),METRIKA_COUNTER_ID(lista —metrika_counters) — definir via*_set_credentials, ou passar em cada chamada. - Alternativa manual: obter token via implicit-flow (
response_type=token) e salvar emYANDEX_OAUTH_TOKEN— mas sem refresh ele expira (Webmaster ~6 meses, Metrica ~1 ano).
Limitações da API do Yandex (não são bugs dos servidores): filtro por URL no Webmaster existe apenas em query-analytics (dados ~2 semanas); endpoint de "consultas recomendadas" na API v4 não existe — ywm_recommended_queries aproxima via demanda (DEMAND) + déficit de cliques; frases de busca na Metrica são majoritariamente "Não definido" (criptografia).
A-Parser (self-hosted) — SERP e centenas de parsers através da sua própria instância
- Sua própria instância em execução do A-Parser (licença + servidor) — o bridge gerencia, mas não hospeda nem faz proxy.
- No A-Parser: Settings → API — ativar o servidor API, anotar a porta (geralmente 9091) e a senha.
APARSER_URL=http://<IP-инстанса>:<порт>/API(obrigatoriamente com o caminho/API),APARSER_PASSWORD= senha do mesmo local →aparser_set_credentials.- Verificação:
aparser_ping, depoisaparser_status(prontidão da instância + proxies vivos).
Nuances: proxies e verificadores de proxy (lotes) são configurados uma única vez na GUI — sem proxies vivos, Google/Yandex banem rapidamente, então as ferramentas serp/suggest fazem preflight e avisam (use_proxy=false — por sua conta e risco); presets e lotes padrão são definidos via env (APARSER_GOOGLE_PRESET, APARSER_YANDEX_PRESET, APARSER_PROXY_CHECKERS, APARSER_USE_PROXY); v1 é síncrono e somente leitura — fila de tarefas e métodos mutantes da API não estão conectados.
Formato de datas e regiões
Datas — YYYY-MM-DD (MSK). Regiões: nome da lista embutida de regiões frequentes ("Moscou", "spb", "Cazaquistão"…) ou id numérico da região do Yandex (213, 225…) — o id numérico sempre funciona. Várias regiões separadas por vírgula são suportadas apenas pelo servidor wordstat; ferramentas SERP xmlstock_*/xmlriver_* aceitam UMA região. Referência completa de ids — ferramenta wordstat_regions_tree.
Onde e como usar
Os servidores são processos stdio comuns, sem vínculo com a máquina. Quatro cenários:
1. Claude Code, localmente
Registrar via claude mcp add --scope user (bloco "Registro no Claude Code" acima) — disponível em todos os projetos e sessões.
2. Claude Code, outra máquina
git clone https://github.com/antohins/seo-tools-mcp.git && cd seo-tools-mcp
pnpm install && pnpm build
# зарегистрировать серверы (блок «Регистрация в Claude Code» выше)
# ключи: скопировать ~/.config/seo-tools-mcp/.env со старой машины (chmod 600)
# ЛИБО выдать в диалоге через <server>_auth_status → <server>_set_credentials
3. Claude Desktop (local)
Em claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/):
{
"mcpServers": {
"xmlstock": { "command": "node", "args": ["/ABS/PATH/seo-tools-mcp/servers/xmlstock/dist/index.js"] },
"wordstat": { "command": "node", "args": ["/ABS/PATH/seo-tools-mcp/servers/wordstat/dist/index.js"] }
}
}
As chaves serão capturadas de ~/.config/seo-tools-mcp/.env automaticamente.
4. Remotamente: claude.ai / Claude Code de qualquer lugar
claude.ai (web/mobile) suporta apenas remote MCP (Streamable HTTP via HTTPS público). Nossos servidores stdio são expostos em um VPS através do bridge supergateway:
# на сервере: клонировать/собрать как в сценарии 2, ключи в ~/.config/seo-tools-mcp/.env
npx -y supergateway --stateful --outputTransport streamableHttp --port 8801 \
--stdio "node /opt/seo-tools-mcp/servers/xmlstock/dist/index.js" # и так для каждого сервера, порты 8801–8805
Depois nginx: TLS + proxy_pass para 127.0.0.1:880X sob caminho secreto (por exemplo /mcp-<длинный-случайный-токен>/xmlstock/) — supergateway deve escutar apenas em localhost. Conexão:
- Claude Code:
claude mcp add --transport http xmlstock https://host/<секретный-путь>/xmlstock/mcp - claude.ai: Settings → Connectors → Add custom connector → mesma URL.
⚠ Caminho secreto — gate mínimo (custom connectors do claude.ai não transmitem cabeçalhos de autorização arbitrários). Atrás do endpoint — todas as chaves dos serviços, portanto: apenas HTTPS, token longo no caminho, access-log separado.
Alternativa para Claude Code sem bridge HTTP — stdio via ssh:
claude mcp add xmlstock --scope user -- ssh root@SERVER node /opt/seo-tools-mcp/servers/xmlstock/dist/index.js
Desenvolvimento
pnpm build # собрать все воркспейсы
pnpm typecheck # только типы
pnpm test # юнит-тесты (vitest, без сети)
pnpm test:live # лайв-смоук по реальным API (нужны креды в конфиге; free-эндпоинты)
node servers/xmlstock/dist/index.js # ручной запуск (stdio)
Testes unitários cobrem a lógica pura: mascaramento de segredos, classificação de erros OAuth, paginação da Metrica/GSC (deduplicação, truncated), filtros, parser SERP, regiões. Live-smoke sobe cada servidor e aciona uma ferramenta gratuita (xmlstock_balance, xmlriver_balance, wordstat_frequency, gsc_list_sites, ywm_hosts, metrika_counters, aparser_ping) — verificação de autorização end-to-end.
Código comum (shared/): cliente HTTP com retries em 429/5xx (3 tentativas, backoff exponencial, Retry-After), carregador de env + config persistente, fábrica de ferramentas de auth, Yandex-OAuth com auto-refresh, helpers JSON MCP, contador de consumo de chamadas pagas. XMLStock adicionalmente faz retry dos seus códigos "temporários" no corpo do XML; código 15 ("nada encontrado") é tratado como resultado vazio.
Build dos servidores — tsup: shared/ é embutido no dist/index.js único de cada servidor (dependências de runtime permanecem externas), portanto o pacote npm é autossuficiente.
Publicação no npm (para mantenedores)
Cada servidor é publicado como um pacote separado seo-tools-mcp-<сервер>; shared/ é privado e não vai para o npm (embutido nos servidores). Mantemos as versões de todos os servidores sincronizadas.
npm login
pnpm -r build # shared (tsc) → серверы (tsup-бандл)
pnpm -r publish --access public # публикует 8 серверов; private-пакеты (shared, корень) пропускаются
pnpm publish substitui automaticamente as versões reais no lugar de workspace:* e não permite publicar com árvore de trabalho suja.
Bump de versão — apenas via package.json raiz: edite a versão lá e execute pnpm version:sync, que distribui para todos os 42 locais (package.json e server.json de cada servidor, literal em new McpServer({ version }), manifestos de plugins). pnpm -r exec npm version patch NÃO serve para isso: atualizará apenas os pacotes dos servidores, o restante ficará na versão antiga, e pnpm version:check no CI falhará. Verificar sem gravar — pnpm version:check.
Contribuição
PRs são bem-vindos — veja CONTRIBUTING.md. Histórico de alterações — CHANGELOG.md. Vulnerabilidades — de forma privada via Security Advisories (detalhes — SECURITY.md).
Licença
MIT © antohins