SEO MCP
Servidor MCP para evidencia SEO — auditoría en página, rastreo, GSC, PageSpeed, SERP opcional
Documentación
mcp-server-seo
Servidor MCP en Rust para evidencia SEO utilizado por Grok Build y Claude Code: auditoría on-page, robots/sitemap, rastreo cortés, PageSpeed Insights, Google Search Console, SERP de pago opcional.
stdio + JSON-RPC a través de rmcp. Sin Docker.
Dos binarios comparten el mismo motor:
| Binario | Rol |
|---|---|
seo | CLI sin interfaz (doctor, tool, audit daily|weekly, mail) |
mcp-server-seo | Servidor MCP stdio para agentes de IA |
Compilación
cargo build --release
install -Dm755 target/release/seo ~/.local/bin/seo
install -Dm755 target/release/mcp-server-seo ~/.local/bin/mcp-servers/mcp-server-seo
Cron / SeoAuditBot usa seo. Los agentes siguen usando mcp-server-seo.
Configuración
Opcional: ~/.config/mcp-server-seo/config.toml (ver config.example.toml).
mkdir -p ~/.config/mcp-server-seo
cp config.example.toml ~/.config/mcp-server-seo/config.toml
chmod 600 ~/.config/mcp-server-seo/config.toml
Las herramientas de la Fase 1 funcionan con cero claves. GSC necesita un JSON de cuenta de servicio; PageSpeed necesita una clave API gratuita; SERP necesita Serper (opcional).
Herramientas (resumen)
| Grupo | Herramientas |
|---|---|
| Fundamentos | status, sites_list, site_resolve |
| On-page | page_audit (mode=quick|full, target_keyword), page_text, redirect_trace, robots_check, sitemap_*, extract_structured_data, schema_validate, link_check, entity_coverage |
| Rastreo / grafo | crawl_run (reanudable, seed_sitemap), crawl_report, crawl_results, crawl_diff, sitemap_coverage, sitemap_build, internal_link_graph (huérfanos reales) |
| Local / arquitectura | url_architecture_plan, nap_consistency (primero esquema), citation_prospects, gbp_audit, gbp_reviews_snapshot, local_audit |
| Contenido / KW | content_brief (basado en SERP), keyword_research (clasificado), keyword_volumes, keyword_intent, keyword_suggest |
| Autoridad | authority_snapshot (gratis, Open PageRank), backlink_overview (de pago, restringido) |
| Rendimiento | pagespeed_audit |
| GSC | gsc_*, gsc_opportunities, gsc_trends, log_event |
| SERP / ranking | serp_fetch (num, paquete local), rank_history (serie), rank_watch |
| Compuestos | page_snapshot, page_history, audit_page, audit_site, verify_live, rank_diagnosis |
| Bucle de corrección | findings_list, findings_diff (por defecto las dos últimas ejecuciones), url_to_source |
Playbook de agente recomendado, primero gratuito (v0.7)
page_auditmode=full(+target_keyword) en la página de inicio + plantillas clavepage_texten cualquier página cuyo contenido necesites evaluar — la auditoría devuelve recuentos, esto devuelve las secciones realescrawl_runconseed_sitemap=true→internal_link_graph; sicoverage.truncated, vuelve a llamar conresume_crawl_idhasta que la frontera se agote, luego leetrue_orphanslocal_auditpara NAP/GBP/autoridad/reseñas en una sola pasadaauthority_snapshotantes de concluir que una página limpia "solo necesita más on-page" — un veredicto de déficit significa enlaces, no pulidoserp_fetchuna vez por consulta objetivo (~$0.001,confirm=YES-PAY) →content_brieflee la SERP almacenada para preguntas PAA y H2 respaldados por competidoresrank_diagnosiscuando una palabra clave específica rinde por debajo de lo esperado — clasifica indexación vs relevancia vs autoridad vs técnicoverify_livedespués del despliegue, luegolog_eventpara que el movimiento tenga una causa asociada- Próxima sesión:
findings_diff(sin IDs de ejecución) —fixedvsnew/regressed.url_to_sourcemapea una URL al archivo bajo[[sites]].source_root
Bucle semanal (programa desde tu cliente MCP — este servidor no ejecuta demonios)
gsc_trends site=<property> refresh=true # stores today's snapshot, returns movers
rank_watch action=run confirm=YES-PAY # re-checks tracked queries
Lee movers_up / movers_down junto al events que registraste.
Sitio nuevo, sin historial de GSC (~$0.10)
keyword_research seed=<service> geo=<city> mode=all
keyword_volumes keywords=[...] confirm=YES-PAY # one call, cached 90 days
serp_fetch <top terms> confirm=YES-PAY # unlocks difficulty + SERP clustering
keyword_research ... # now returns a ranked shortlist
url_architecture_plan / content_brief # human approval before publish
La publicación de contenido permanece en el CMS — este servidor es evidencia + briefs, no un redactor.
Seguridad
- SSRF: solo http(s) público; IPv4+IPv6 privadas/reservadas bloqueadas; saltos de redirección re-verificados
sitemap_build: escrituras solo bajostorage.data_dir(out_pathrelativo)- Envío GSC:
confirm=YES-SUBMIT(API de sitemaps — no Inspección de URL) - SERP de pago:
dry_run=truepor defecto;confirm=YES-PAY+ libro de presupuesto - Autoridad de pago (
backlink_overview): misma puerta, libro de presupuesto[authority]separado; la ejecución en seco hace cero llamadas al proveedor y el libro registra el costo real informado por el proveedor - HTML estático:
rendered: false— usaagent-browserpara JS
Claves opcionales (v0.7)
| Clave | Desbloquea | Costo |
|---|---|---|
authority.open_pagerank_api_key | authority_snapshot, paso de autoridad en local_audit, veredictos rank_diagnosis, dificultad de palabras clave | gratis (domcop) |
authority.dataforseo_login / _password | brecha de enlaces backlink_overview, keyword_volumes | pago por uso, con tope de presupuesto |
serp.api_key | serp_fetch / rank_watch → fundamenta content_brief, dificultad de palabras clave, comprobaciones de presencia de citas | ~$0.001/consulta |
local.places_api_key | calificación gbp_reviews_snapshot, velocidad de reseñas, brecha de competidores | nivel gratuito + tope mensual de llamadas |
gsc.credentials_file | gsc_* incl. historial gsc_trends y gsc_opportunities | gratis |
Verifica antes de confiar en los números: el costo de crédito de tu proveedor de SERP para num > 10 (serp.num_100_multiplier), el keywords.location_code de DataForSEO para tu país, y el precio actual de los campos de Places API. Los tres son valores de configuración, no están codificados.
No reimplementar
Usa MCPs hermanos: google-analytics, google-adwords, cloudflare, namecheap, agent-browser.
Clientes
Ya registrado como seo en Grok Build / Claude Code (reinicia los clientes después de recompilar).
Pruebas
cargo test --release
./tests/test-stdio.sh
Plan
Ver PLAN.md (fusionado Grok + Fable + Kimi + enmiendas de crítica).
Diseño de módulos (v0.7)
src/
bin/seo.rs # CLI (doctor, tool, audit daily|weekly, mail)
bin/mcp_server_seo.rs
server/ # thin MCP tool-router only (no SEO logic)
params.rs # all tool input schemas
dispatch/ # named-tool router + one exec file per handler group
playbooks.rs # daily/weekly audits; ok=false on step errors
mod.rs # SeoServer, shared helpers, chained tool_router()
handlers/ # #[tool] wrappers → run_named; one sub-router per file
# (site, page, crawl, pagespeed, gsc, serp, audit,
# findings, content, authority, local)
tools/ # business logic per concern
page/ # parse, og probe, structured data, text extraction, audit
crawl/ # BFS crawl + report builder
local/ # nap, citations, gbp, local_audit
gsc/ # client (JWT) + ops (analytics/inspect/sitemaps)
authority/ # open pagerank (free) + dataforseo (paid) adapters
audit/ # composites: page, site, verify_live, rank_diagnosis
source_map.rs # URL → repo file (convention presets, sandbox)
serp_evidence.rs# stored-SERP parser shared by briefs/keywords
html_dom.rs # shared HTML extract helpers incl. main-text extraction
…
rules/ # pure rules (checklist, schema, patterns, intent, relevance, issue)
storage/ # SQLite split by domain (crawls, snapshots, spend, authority,
# keywords, gsc, rank, places, events,
# findings/{persist,extract,query,family}) over one shared conn
http.rs / config.rs / site.rs / util.rs
Regla: sin archivos God — la lógica vive bajo tools/* / rules/*; server/ no implementa algoritmos SEO. Los constructores de problemas compartidos viven en rules/issue.rs.