feat(wordpress): novo MCP mcp-rank-math - escrita/gestao Rank Math SEO
27 tools via WP-CLI/SSH (bridge SQL para tabelas planas + wp eval-file para dados serializados/side-effects): meta de post/taxonomia, schema markup, redirects (via RankMath\Redirections\DB), modulos, sitemap, 404 monitor, analytics GSC, IndexNow, validacao SEO ao vivo por HTTP. Cobre exactamente o que o MCP oficial rank-math-mcp (abilities rank-math/* via WP Abilities API, documentado nesta sessao por outro agente em rank-math/SKILL.md secao 17) nao cobre: esse e read-only/ analise (audit-site-seo, get-post-schema, scores, AI Visibility); este e escrita/gestao (redirects, modulos, 404s, sitemap, options). Os dois coexistem - rank-math/SKILL.md secao 17.4 actualizada com tabela de quando usar qual dos tres caminhos (rank-math-mcp / mcp-rank-math / WP-CLI). Testado ponta-a-ponta em producao 19-08-2026: leituras com dados reais (383 posts score bom, 21 modulos activos, 3 redirects, sitemap 9 entradas) e escritas verificadas sem mutar dados (no-op em option/meta existentes, ciclo completo create+delete de um redirect de teste). Bug real apanhado no smoke test: rank_math_modules tem chaves nao- sequenciais na BD -> json_encode serializa como objecto, nao array - normalizado em normalizeStringArray() antes de considerar pronto.
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
---
|
||||
name: mcp-rank-math
|
||||
description: MCP dedicado (node stdio, ligação `rank-math` em ~/.omp/agent/mcp.json) para o Rank Math SEO/Rank Math Pro em descomplicar.pt via WP-CLI/SSH. 27 tools tipadas — meta de post/taxonomia, schema markup, redirects, módulos, sitemap, 404 monitor, analytics GSC, IndexNow, validação SEO ao vivo. Preferir a este MCP em vez dos snippets manuais `wp eval`/`wp db query` da skill `/rank-math` sempre que a operação já esteja coberta aqui. Usar quando "rank math", "meta SEO", "schema markup", "redirects seo", "404 monitor", "módulos rank math", "seo score", "sitemap rank math", "indexnow", "validar seo página".
|
||||
layer: wiki
|
||||
---
|
||||
|
||||
# /mcp-rank-math — MCP dedicado Rank Math SEO / Rank Math Pro
|
||||
|
||||
Projecto em `/media/ealmeida/Dados/Dev/mcp-rank-math/` (TypeScript, SDK MCP oficial, stdio).
|
||||
Substitui a execução manual dos comandos `wp eval`/`wp db query`/`wp option patch` documentados na
|
||||
skill `/rank-math` por 27 tools tipadas, com validação de input e capability boundaries claras.
|
||||
**Ambas as skills coexistem** — `/rank-math` continua a ser a referência para o que ainda não tem
|
||||
tool dedicada (ver "Fora do âmbito" abaixo); este MCP é o caminho preferido para tudo o resto.
|
||||
|
||||
## Porquê duas pontes internas (SQL vs PHP-eval)
|
||||
|
||||
Rank Math guarda a maior parte dos dados **serializados em PHP** — a tabela
|
||||
`rank_math_redirections.sources`, quase todas as `rank-math-options-*`, e qualquer meta de
|
||||
post/term com valor array (`rank_math_robots`, `rank_math_schema_*`). SQL directo lê o blob
|
||||
serializado em bruto; só o WordPress core (`get_option()`, `get_post_meta()`,
|
||||
`maybe_unserialize()`) descodifica isso correctamente. Por isso o MCP usa duas pontes:
|
||||
|
||||
- **SQL directo** (`wp db query --raw`) — só contra tabelas confirmadas 100% planas:
|
||||
`posts`/`postmeta` (joins de auditoria), `rank_math_404_logs`, `rank_math_analytics_gsc`.
|
||||
- **`wp eval-file -`** (PHP inteiro recebido via STDIN, nunca interpolado na linha de comando) —
|
||||
tudo o resto: meta com arrays, schema, redirects (via `\RankMath\Redirections\DB`, para disparar
|
||||
os side-effects certos, nunca `INSERT`/`UPDATE` SQL directo nessa tabela), módulos, options com
|
||||
`wp option patch` (nunca `wp option update`, que substitui a option inteira e apaga as outras
|
||||
sub-chaves).
|
||||
|
||||
Valores dinâmicos (títulos, descrições, schema JSON) nunca são interpolados directamente numa
|
||||
string PHP: viajam como JSON (`json_decode(...)` no lado PHP), evitando tanto injecção como o bug
|
||||
clássico de `"$5 off"` a ser lido como interpolação de variável dentro de uma string PHP de aspas
|
||||
duplas.
|
||||
|
||||
## Gotcha real de produção — `rank_math_modules`
|
||||
|
||||
A option tem **chaves não-sequenciais** (buracos de remoções antigas de módulos sem
|
||||
`array_values()`). `wp option get --format=json` faz `json_encode()` directo do array PHP
|
||||
subjacente — um array PHP com chaves não-consecutivas serializa como **objecto** JSON
|
||||
(`{"0":"a","3":"b"}`), não array. O MCP normaliza isto internamente (`rm_get_plugin_status`,
|
||||
`rm_list_modules`); se algum dia se ler `rank_math_modules` directamente via `wp option get`
|
||||
fora do MCP, **não assumir que a saída é sempre um array JSON**.
|
||||
|
||||
## Tools (27)
|
||||
|
||||
**Estado/auditoria:** `rm_get_plugin_status` (versões Free/Pro, licença, nº módulos activos),
|
||||
`rm_audit_missing_meta`, `rm_audit_seo_scores`, `rm_get_top_404s`, `rm_clear_404_logs`
|
||||
(`confirm: true` para apagar tudo)
|
||||
|
||||
**Meta de post:** `rm_get_post_meta`, `rm_update_post_meta` (parcial — `null` num campo apaga-o),
|
||||
`rm_bulk_fill_missing_meta` (`dry_run: true` por omissão — só lista, não escreve)
|
||||
|
||||
**Meta de taxonomia:** `rm_get_term_meta`, `rm_update_term_meta`
|
||||
|
||||
**Schema markup:** `rm_get_post_schema`, `rm_set_post_schema` (`schema_type` alfanumérico —
|
||||
"Article", "FAQPage", "Product", "LocalBusiness", etc.), `rm_delete_post_schema` (omitir
|
||||
`schema_type` apaga todos — requer `confirm: true`)
|
||||
|
||||
**Options/módulos:** `rm_get_option`, `rm_set_option` (sempre `wp option patch` internamente —
|
||||
nunca perde sub-chaves irmãs), `rm_list_modules`, `rm_toggle_module`
|
||||
|
||||
**Redirects:** `rm_list_redirects`, `rm_create_redirect`, `rm_update_redirect`,
|
||||
`rm_delete_redirects`
|
||||
|
||||
**Sitemap:** `rm_regenerate_sitemap`, `rm_list_sitemap_urls` (HTTP directo ao `sitemap_index.xml`
|
||||
público — sem SSH, reflecte exactamente o que o Google vê)
|
||||
|
||||
**IndexNow:** `rm_submit_indexnow` (HTTP directo à API do IndexNow; só lê a chave via WP-CLI)
|
||||
|
||||
**Analytics:** `rm_get_analytics_overview` — degrada com `available:false` se o módulo/tabela GSC
|
||||
não existir, em vez de erro
|
||||
|
||||
**Backup/validação:** `rm_export_seo_snapshot` (devolve os dados; não escreve ficheiro no
|
||||
servidor), `rm_validate_live_seo` (fetch directo ao URL publicado — título, meta description,
|
||||
canonical, robots, OG tags, tipos JSON-LD tal como renderizados, sem SSH)
|
||||
|
||||
## Segurança
|
||||
|
||||
- `rm_clear_404_logs` sem `older_than_days` e `rm_delete_post_schema` sem `schema_type` exigem
|
||||
`confirm: true`.
|
||||
- `rm_set_option` nunca aceita substituir a option inteira — só `wp option patch` num caminho de
|
||||
sub-chave.
|
||||
- `rm_submit_indexnow` e o ramo de escrita de `rm_update_redirect`/`rm_create_redirect` têm efeito
|
||||
público real (notificação a motores de busca, redireccionamento de tráfego real) — confirmar
|
||||
intenção antes de invocar em massa.
|
||||
|
||||
## Fora do âmbito (usar `/rank-math` para estes)
|
||||
|
||||
WooCommerce SEO em massa (categorias de produto, atributos — os padrões `wp eval` já documentados
|
||||
na skill `/rank-math` §9 continuam válidos), News/Video Sitemap (meta dedicada por post, §10),
|
||||
hooks/filtros PHP persistentes (§11), migração Yoast→Rank Math (§migração), provisioning inicial
|
||||
de um site novo (§13 — sequência de setup, não uma operação repetível), gestão de licença/ligação
|
||||
de conta Pro (ver skill `/full-cliente`).
|
||||
|
||||
## Verificação
|
||||
|
||||
Construído e testado ponta-a-ponta contra produção 19-08-2026: leituras confirmadas com dados
|
||||
reais (distribuição de scores 383 bons/36 ok/116 fracos, 404s reais, 21 módulos activos, sitemap
|
||||
com 9 entradas, validação ao vivo de uma página publicada com título/description/canonical/OG
|
||||
idênticos ao que `rm_get_post_meta` devolve para o mesmo post). Escritas testadas sem alterar
|
||||
dados reais: `rm_set_option`/`rm_update_post_meta` escreveram o mesmo valor já existente (no-op
|
||||
real, confirmado por leitura pós-escrita); ciclo completo `rm_create_redirect`→
|
||||
`rm_delete_redirects` com um redirect de teste, confirmado removido a seguir. Um bug real
|
||||
(`rank_math_modules` object-vs-array) foi apanhado neste smoke test e corrigido antes de
|
||||
considerar o MCP pronto — ver README do projecto.
|
||||
|
||||
## Nota
|
||||
|
||||
`rm_get_post_meta`/`rm_get_term_meta` num ID inexistente devolvem campos vazios em vez de erro
|
||||
(comportamento do próprio `get_post_meta()`/`get_term_meta()` do WordPress core, que não avisa
|
||||
para ID inválido) — confirmar a existência do post/termo antes de interpretar "tudo vazio" como
|
||||
"sem meta definida".
|
||||
Reference in New Issue
Block a user