---
title: "Servidor MCP de Ahrefs: configuración para Claude, Codex y los demás"
description: "Hay dos servidores MCP de Ahrefs y dos tipos de clave, y la combinación equivocada falla en silencio. La conexión para cada cliente y las trampas que cuestan dinero."
author: "Matthias Meyer"
published: 2026-08-03
updated: 2026-08-03
language: es
tags: ["ahrefs", "mcp", "claude-code", "codex", "seo", "api"]
canonical: "https://studiomeyer.io/es/blog/ahrefs-mcp-server-setup"
markdown_versions: ["https://studiomeyer.io/de/blog/ahrefs-mcp-server-setup.md", "https://studiomeyer.io/en/blog/ahrefs-mcp-server-setup.md", "https://studiomeyer.io/es/blog/ahrefs-mcp-server-setup.md"]
publisher: "StudioMeyer, https://studiomeyer.io (llms.txt: https://studiomeyer.io/llms.txt)"
---

# Servidor MCP de Ahrefs: configuración para Claude, Codex y los demás

Lo primero que ocurre cuando conectas Ahrefs a un cliente de IA es que no ocurre nada. Ningún error, ninguna herramienta, solo un servidor que parece conectado y se queda mudo. En mi caso la causa era trivial: Ahrefs mantiene dos servidores MCP distintos y dos tipos distintos de clave de API, y solo una de las cuatro combinaciones posibles es la que quieres hoy. Nadie te dice cuál has elegido.

Esa es la versión corta de por qué existe esta guía. La larga es que pasé un ciclo de suscripción enviando unas 1.100 llamadas registradas por este sistema, y lo que más tiempo me costó no fue el análisis SEO. Fue la instalación.

## A qué te conectas realmente

Ahrefs opera un servidor MCP alojado en `https://api.ahrefs.com/mcp/mcp`. Habla Streamable HTTP, el transporte actual de la especificación del Model Context Protocol y el que soporta cualquier cliente serio. SSE está obsoleto y no conviene construir nada nuevo sobre él.

Detrás de ese endpoint está casi todo lo que normalmente consultas en la interfaz web de Ahrefs: Site Explorer para backlinks y palabras clave orgánicas, Keywords Explorer para volumen y dificultad, Rank Tracker, Site Audit, y la integración con Search Console si tienes una cuenta vinculada. En mi instalación eran 130 herramientas invocables, más de las que anuncian las páginas comerciales, porque el servidor ha ido creciendo.

Conviene saber dos cosas antes de conectar nada. El acceso empieza en el plan Lite, así que una cuenta de prueba gratuita no entra. Y cada llamada facturable consume del mismo presupuesto mensual de unidades de API que el uso normal de la API, lo que significa que tu asistente de chat y tus tareas programadas comen del mismo plato. La facturación se divide en tres: bastantes endpoints no cuestan nada, algunos cobran una tarifa fija por petición y el resto cobra por fila. La última sección trata de distinguirlos.

## Dos servidores, dos tipos de clave, un fallo silencioso

Esta es la parte que me costó la primera tarde.

Existe un servidor local más antiguo, publicado como `@ahrefs/mcp` en npm y como `ahrefs/ahrefs-mcp-server` en GitHub. Ese repositorio está archivado, y su readme contiene una frase que conviene leer dos veces: funciona únicamente con claves de API v3, y no funciona con claves MCP.

El servidor alojado se comporta justo al revés. Quiere una clave con ámbito MCP, que se genera aparte en tu cuenta de Ahrefs. Ahrefs afirma sin rodeos que las claves de API y las claves MCP no son intercambiables.

La matriz queda así. Dos casillas funcionan, pero solo una de ellas es una elección sensata hoy:

| | Clave API v3 | Clave con ámbito MCP |
|---|---|---|
| **Local `@ahrefs/mcp`** | funcionaba, repositorio ahora archivado | falla |
| **Remoto `/mcp/mcp`** | falla | **correcto** |

La combinación archivada no está tanto rota como abandonada. Sigue funcionando si ya la tienes, pero no recibe mantenimiento y Ahrefs remite al servidor alojado.

Los modos de fallo son discretos. Una clave MCP apuntada a la API REST devuelve `Unauthorized`, lo cual al menos te dice algo. Un cliente que no completa el handshake suele mostrar el servidor con cero herramientas, y entonces buscas una errata de configuración que no existe.

Si empiezas hoy: servidor alojado, clave con ámbito MCP, y descarta cualquier tutorial que te haga instalar algo por npm.

## Autenticación: OAuth es la vía oficial, Bearer es la útil

Ahrefs documenta OAuth como el camino estándar. Tu cliente abre una ventana del navegador, inicias sesión, y las credenciales quedan guardadas. Para trabajo interactivo está bien y es la opción menos engorrosa.

Se complica en cuanto quieres que un trabajo programado extraiga datos un domingo a las siete de la mañana. OAuth necesita a una persona frente a un navegador para la autorización inicial, y a partir de ahí mantienes una renovación de token que tiene que seguir funcionando sin supervisión. Así que para todo lo desatendido me autentico con un token Bearer y envío la clave MCP directamente en la cabecera `Authorization`. Mismo endpoint, mismas herramientas, sin navegador y sin nada que renovar.

La regla práctica a la que llegué: Bearer para todo lo que deba sobrevivir sin mí, OAuth para el portátil delante del que estoy sentado. Si solo lo usas en chat, acepta el aviso de OAuth y sáltate las secciones siguientes.

## Claude Code

Un comando, y el indicador de ámbito decide si el servidor vive en este proyecto o en tu configuración de usuario.

```bash
claude mcp add --transport http ahrefs https://api.ahrefs.com/mcp/mcp \
  --header "Authorization: Bearer $AHREFS_API_KEY" -s project
```

El ámbito de proyecto escribe en un `.mcp.json` junto al código, que es lo correcto cuando la clave pertenece a un cliente o a un sitio concreto. Ese archivo debe entrar en `.gitignore` antes de que pegues una clave en él, porque la cabecera queda ahí en texto plano.

Dos cosas me costaron tiempo aquí. Las herramientas aparecen como `mcp__ahrefs__<nombre>`, no como `ahrefs.<nombre>`, lo cual importa cuando escribes prompts que nombran una herramienta explícitamente. Y una sesión en marcha carga sus servidores MCP solo al arrancar, de modo que la conexión que acabas de añadir aparece en la siguiente sesión, no en esta. Reinicié tres veces convencido de que la configuración estaba mal.

## Claude Desktop

No hace falta archivo de configuración. Ajustes, luego Connectors, luego Add custom connector, y pegas la URL del endpoint. El client ID y el secreto de OAuth van en los ajustes avanzados, si tu servidor los necesita.

Hay un detalle de arquitectura que sorprende y que cambia lo que puedes conectar. Claude Desktop no alcanza tu servidor MCP desde tu máquina, sino desde la infraestructura en la nube de Anthropic. Para un servicio alojado como Ahrefs eso da igual. Para un servidor que corre en tu propio portátil o detrás de una VPN corporativa lo cambia todo, porque ese servidor tiene que ser accesible desde internet antes de que funcione siquiera.

Las cuentas gratuitas están limitadas a un conector propio; las de pago no.

## Codex

Codex lee `~/.codex/config.toml` de forma global, o un `.codex/config.toml` en un directorio de proyecto marcado como de confianza. Una tabla TOML por servidor, y el transporte se deduce de qué claves defines: un `command` significa stdio, un `url` significa Streamable HTTP.

```toml
[mcp_servers.ahrefs]
url = "https://api.ahrefs.com/mcp/mcp"
bearer_token_env_var = "AHREFS_API_KEY"
```

Fíjate en lo que espera `bearer_token_env_var`. Es el nombre de una variable de entorno, no el token en sí. Si escribes ahí la clave directamente, acabas con un archivo de configuración lleno de secreto y un servidor lleno de nada.

El subcomando `codex mcp add` existe, pero está pensado para servidores stdio. Para un endpoint remoto, editar el TOML es más rápido y más fácil de versionar. Verifica con `codex mcp list`.

## Cursor, VS Code y Windsurf

Los tres hablan el mismo JSON con una diferencia molesta: la clave que contiene la URL. Cursor la llama `url`. VS Code quiere `url` junto a un `"type": "http"` explícito, la misma forma que usa Claude Code. Windsurf la llama `serverUrl`. Todo lo demás del bloque se copia sin cambios, así que una configuración que funciona en un editor está a treinta segundos de renombrado de funcionar en el siguiente.

VS Code soporta MCP de forma nativa desde la 1.99, a través de Copilot Chat. Windsurf lo incorporó a principios de año. Si tu equipo está repartido entre editores, escribe el bloque una vez y guarda las tres variantes como snippet.

## Sin ningún cliente, de forma desatendida

MCP es un protocolo de sesión, no una llamada REST simple. Inicializas, envías una notificación de inicialización, y solo entonces puedes invocar una herramienta. Cada petición posterior lleva el identificador de sesión que recibiste.

```bash
curl -sD hdr -X POST "$AHREFS_MCP_URL" \
  -H "Authorization: Bearer $AHREFS_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{
       "protocolVersion":"2025-06-18","capabilities":{},
       "clientInfo":{"name":"sm","version":"1"}}}'

SID=$(grep -i '^mcp-session-id:' hdr | awk '{print $2}' | tr -d '\r')

curl -s -X POST "$AHREFS_MCP_URL" \
  -H "Authorization: Bearer $AHREFS_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "MCP-Protocol-Version: 2025-06-18" \
  -H "mcp-session-id: $SID" \
  -d '{"jsonrpc":"2.0","method":"notifications/initialized"}'
```

Tres cosas ahí se hacen mal con facilidad. No te saltes la segunda llamada: el identificador de sesión por sí solo no cierra el handshake, y un servidor que nunca recibió la notificación de inicialización rechaza las llamadas a herramientas. La cabecera `Accept` necesita ambos tipos de contenido aunque nunca pretendas leer un stream. Y a partir de la revisión 2025-06-18, toda petición posterior a la inicialización debe llevar la cabecera `MCP-Protocol-Version`, así que va en la notificación y en cada llamada a herramienta posterior, junto a `mcp-session-id`.

Envolver esto en un pequeño script de shell merece la pena, porque pone los mismos datos a disposición de tareas programadas y agentes que no tienen ninguna interfaz de chat. El mío está publicado como [ahrefs-mcp-kit](https://github.com/studiomeyer-io/ahrefs-mcp-kit) por si prefieres partir de algo que ya funciona. Un aviso por experiencia: si construyes ese script con un valor por defecto de bash como `${ARG:-{}}` para el argumento JSON, el emparejamiento de llaves dentro del valor por defecto añade en silencio una llave de cierre sobrante y produce JSON inválido. La llamada falla sin salida y sin error. Define el valor por defecto en una línea aparte.

## Tu plan decide tu límite de filas, y ahí está lo caro

Esta es la sección que ojalá hubiera leído primero, porque explica un error que me costó un presupuesto mensual entero en una sola mañana.

Ahrefs escalona dos cosas por nivel de suscripción: cuántas unidades recibes al mes, y cuántas filas puede devolver una única petición.

| Plan | Unidades al mes | Filas por petición |
|---|---:|---:|
| Lite | 100.000 | 100 |
| Standard | 400.000 | 250 |
| Advanced | 1.000.000 | 500 |
| Enterprise | 2.000.000 | sin límite |

Esas cifras cambiaron el 28 de abril de 2026, y cambiaron mucho. Lite pasó de 25.000 unidades a 100.000 y de 10 filas a 100. Standard pasó de 150.000 a 400.000 unidades y de 25 filas a 250. Advanced duplicó sus unidades y pasó de 100 filas a 500.

Ahora ponlo junto a cómo se factura. Una llamada cuesta un mínimo de 50 unidades, y por encima de ese suelo pagas por fila, multiplicado por las columnas que hayas pedido. Las columnas premium como `volume`, `keyword_difficulty` y `traffic_domain` añaden unas diez unidades por fila cada una.

Junta ambos hechos y aparece la trampa. La llamada más cara de todo mi registro se ejecutó con un límite de 250 filas. No es una cifra que eligiera tras pensarlo. Es exactamente el límite de filas del plan que tenía, y la usé porque era el máximo disponible. Cada una de esas llamadas costó 5.250 unidades. La misma consulta con 50 filas habría costado 1.050 y me habría dicho lo mismo, porque las filas 51 a 250 eran ruido de cola larga que nunca llegué a usar.

El límite de filas no es una recomendación. Es un techo, y desde abril ese techo está hasta diez veces más alto que antes. Para código con un límite explícito eso es inofensivo: 50 sigue siendo 50. Lo nota quien no pasa ningún límite, quien pide el máximo vigente en cada momento, y quien tiene una consulta que antes quedaba cortada por el techo antiguo y ahora devuelve las diez veces más filas completas. Los tres casos son habituales en scripts escritos antes de la primavera, y ninguno se ve distinto en el código.

Fija el límite según lo que vayas a leer de verdad. Para expansión de palabras clave ahora empiezo en 50 y solo subo cuando un resultado quedó visiblemente cortado en el borde y las filas extra cambian algo.

## Diez trampas que me costaron una ejecución cada una

Ninguna está en la documentación de forma que la encuentres antes de tropezar. Todas produjeron o un error que hubo que descifrar o, peor, un resultado vacío que parecía un hallazgo.

**`where` es JSON, nunca una expresión en texto.** Escribir `"position>3 and position<15"` devuelve `bad where: invalid JSON syntax`. El mismo filtro en JSON necesita una cláusula por condición:

```json
{"and":[{"field":"position","is":["gt",3]},
        {"field":"position","is":["lt",15]}]}
```

Los operadores son `gt`, `gte`, `lt`, `lte`, `eq`.

**`select` cambia de tipo entre herramientas.** Site Explorer y Keywords Explorer quieren una cadena separada por comas. `batch-analysis` quiere un array. Confundirlos da `column '["domain"' not found` en un sentido y `expected array but got string` en el otro.

**No transcribas los acentos ni las diéresis.** La coincidencia de palabras clave es literal. Un término alemán escrito con `ue` en lugar de `ü` devuelve cero filas y parece una palabra clave muerta. Lo mismo vale para las tildes en español.

**El filtro de país puede borrar la verdad en silencio.** Filtrar palabras clave orgánicas por país devolvió cero filas para un dominio que demostrablemente posiciona, porque sus posiciones estaban en otros países. Pagué 50 unidades por una respuesta vacía y casi concluyo que el dominio no posicionaba para nada. Extrae sin el filtro y toma `keyword_country` como columna.

**Usa `mode: "subdomains"` por defecto.** En cualquier sitio cuyo dominio raíz redirige a www, `mode: "domain"` mide el host exacto y devuelve ceros fantasma. He visto un dominio informar de unos cientos de backlinks y ningún tráfico en modo domain frente a veintidós mil backlinks en modo subdomains.

**`volume-history` acepta `keyword`, en singular.** Pasar `keywords` falla con `required arguments [keyword] are missing`. Veintiséis llamadas en una tanda, todas rechazadas, todas por una letra.

**Hoy no es un `date_to` válido.** Incluso los endpoints agregados rechazan la fecha actual con `bad date_to`. Usa la de ayer.

**Nunca busques una incidencia de Site Audit por su nombre.** Los nombres no son únicos. Encontré el mismo nombre asociado a dos identificadores distintos, uno de ellos permanentemente vacío. Toma el identificador de tu propia respuesta de incidencias en lugar de buscar por texto.

**Las tablas de detalle vacías de Search Console no significan conexión rota.** Los endpoints de detalle se materializan con unas seis semanas de retraso, así que una consulta de los últimos 30 días vuelve vacía mientras los agregados están al día. He visto a dos personas concluir que su integración estaba muerta cuando funcionaba perfectamente.

**Trata `org_traffic` como un modelo, no como una medición.** Se estima a partir de las palabras clave del índice de Ahrefs multiplicadas por una curva de clics. Lo que el índice no recoge sencillamente no existe en esa cifra. En los sitios de nicho que contrasté con datos reales de Search Console se quedaba muy por debajo, en un caso por un factor que no habría creído sin ver ambas cifras juntas. En tus propios dominios, Search Console es la verdad. En dominios ajenos, etiquétalo como suelo y no como cifra.

## Agota las superficies gratuitas antes de gastar

El mejor hábito que me llevo: todo lo asociado a un proyecto propio verificado es gratis o casi gratis, y casi nadie lo toca.

En todo mi registro, los endpoints de Search Console, los de gestión y la consulta gratuita de domain rating costaron en conjunto cero unidades y devolvieron algo menos de 6.000 filas. Hay exactamente una excepción y es una trampa: `gsc-anonymous-queries` lleva el mismo prefijo `gsc-` pero factura desde 50 unidades por llamada y en un sitio pequeño no devuelve casi nada. `site-audit-page-explorer` cuesta 50 unidades fijas por petición independientemente de cuántas filas vuelvan, lo que sobre casi 10.000 filas salió a un tercio de unidad por fila, con más de veinte campos técnicos por URL. El rank tracker y la información de suscripción también son gratuitos.

Al otro lado de la cuenta: tres herramientas, todas consultas de palabras clave y backlinks facturadas por fila, supusieron el 78 por ciento de todo lo que gasté. Las superficies gratuitas y baratas devolvieron unas 18.000 filas por 3.400 unidades. Las tres caras devolvieron 30.000 filas por 592.000. Eso es un factor de unas cien veces de valor con el mismo presupuesto.

El orden, entonces: comprueba las unidades restantes, agota las superficies gratuitas del proyecto, profundiza con las herramientas de tarifa plana, y solo después recurre a las facturadas por fila, con un límite que hayas elegido a conciencia.

## Lo que le diría a alguien que empieza mañana

Genera una clave con ámbito MCP, apunta tu cliente al endpoint alojado y no instales nada. Usa OAuth si trabajas en chat, Bearer si algo tuyo corre según un calendario. Antes de tu primera consulta real, abre la herramienta de información de suscripción y lee tu límite de filas del plan en lugar de suponerlo.

Y luego apunta tus propias cifras. Los costes de este artículo son lo que medí en un plan a lo largo de 1.102 llamadas, y el modelo de precios se movió notablemente en abril. Cada respuesta lleva incorporado su coste real, o sea que la herramienta te dice lo que ha cobrado si te molestas en mirar. Dos días registrando ese campo me enseñaron más sobre dónde se va el dinero que cualquier cantidad de documentación.

## Seguir leyendo, Claude + Claude Code

- [Transportes MCP: stdio frente a HTTP, y qué acaba de cambiar](https://studiomeyer.io/es/blog/mcp-stdio-vs-http.md)
- [Leer y analizar documentos con Claude](https://studiomeyer.io/es/blog/analyze-documents-with-claude.md)
- [Automatizar las partes repetitivas de tu semana con Claude](https://studiomeyer.io/es/blog/automating-tasks-with-claude.md)
- [Claude en 2026: modelos, apps, Claude Code y la API](https://studiomeyer.io/es/blog/claude-guide-2026.md)
