# Flujo de contenido automático con el servidor MCP de Endata

> Apunta cualquier cliente MCP a `https://app.endata.com/mcp` con una clave de API del proyecto como token bearer. Obtienes 77 operaciones como herramientas, las mismas de la API REST. Un flujo son cinco llamadas: `questions_list`, `question_research`, `answer_read`, `prepare_action`, `answer_publish`. Publicar requiere la confirmación de una persona o un permiso sin supervisión que otorgue un propietario a la clave. Además, cada publicación de Endata es en sí un servidor MCP público y sin clave en el que los agentes pueden buscar.

Actualizado el 2026-10-12

Endata expone todo su flujo editorial como herramientas MCP: preguntas, investigación, borradores, aprobaciones, publicación y difusión. Esta guía conecta un agente y arma un flujo que convierte la pregunta de un cliente en una respuesta publicada y con fuentes, con una persona que confirma el paso que se hace público.

- Un espacio de trabajo en Business o Agency
- Una clave de API del proyecto (`fsk_…`)
- Un cliente MCP: Claude Code, Codex o Node.js 20+

## Endata tiene dos servidores MCP. ¿Cuál necesitas?

|   | Servidor del espacio de trabajo | Servidor de la publicación |
| --- | --- | --- |
| Dirección | `https://app.endata.com/mcp` | `https://<tu-publicacion>/mcp` |
| Autenticación | Clave de API del proyecto como bearer | Ninguna |
| ¿Puede escribir? | Sí, dentro de los permisos de la clave | No, solo lectura |
| Herramientas | 77 operaciones más `prepare_action` | `search_answers`, `get_answer`, `list_questions`, `list_changes` |
| Límite de solicitudes | 120 solicitudes por minuto por clave | 60 por minuto por dirección |
| Úsalo para | Ejecutar tu flujo editorial desde un agente | Dejar que cualquier agente lea lo que publicaste |

La mayor parte de esta guía trata del servidor del espacio de trabajo. El servidor de la publicación no requiere configuración alguna: existe desde el momento en que publicas y se anuncia en `/.well-known/mcp.json`.

## Paso 1: Crea una clave de API con permisos acotados

**En Configuración → Desarrollador → Claves API, crea una clave solo con los permisos que necesita el flujo.**

Las claves pertenecen a un proyecto y empiezan con `fsk_`. Las crea un propietario y cada una lleva permisos. Las herramientas fuera de los permisos de una clave ni siquiera se le muestran al agente, así que una clave acotada también da una lista de herramientas más corta y clara.

| Permiso | Qué permite |
| --- | --- |
| `published:read` | Leer artículos y respuestas publicados |
| `editorial:read` | Leer preguntas, borradores, investigaciones y analíticas |
| `editorial:write` | Agregar preguntas, iniciar investigaciones, guardar borradores |
| `editorial:approve` | Aprobar una revisión de un artículo |
| `publishing:manage` | Publicar, despublicar y compartir |

Para este flujo, otorga `editorial:read`, `editorial:write` y `publishing:manage`. Deja desactivados `administration:manage` y `organization:manage`, a menos que el agente realmente administre dominios, integraciones o miembros del equipo.

> **Mantén la clave en el servidor** Una clave actúa en nombre de todo el proyecto. Guárdala en una variable de entorno, nunca en código del navegador ni en un repositorio. Las claves pueden tener fecha de vencimiento y se verifica si fueron revocadas en cada solicitud.

## Paso 2: Conecta tu cliente MCP

**Agrega el servidor a Claude Code, a Codex o a cualquier cliente que hable Streamable HTTP.**

### Claude Code

```json
{
  "mcpServers": {
    "endata": {
      "type": "http",
      "url": "https://app.endata.com/mcp",
      "headers": { "Authorization": "Bearer ${ENDATA_API_KEY}" }
    }
  }
}
```

En `.mcp.json`, en la raíz de tu proyecto. Define `ENDATA_API_KEY` en tu shell.

### Codex

```bash
[mcp_servers.endata]
url = "https://app.endata.com/mcp"
bearer_token_env_var = "ENDATA_API_KEY"
```

En `~/.codex/config.toml`.

### Tu propio código

El servidor es Streamable HTTP sin estado y solo acepta POST, así que el SDK oficial se conecta sin manejar sesiones. El pequeño asistente `call` de abajo se usa en todos los pasos siguientes.

```javascript
// npm install @modelcontextprotocol/sdk
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from
  "@modelcontextprotocol/sdk/client/streamableHttp.js";

const publicationId = process.env.ENDATA_PUBLICATION_ID;
const client = new Client({ name: "answer-pipeline", version: "1.0.0" });
await client.connect(new StreamableHTTPClientTransport(
  new URL("https://app.endata.com/mcp"),
  { requestInit: { headers: {
    Authorization: `Bearer ${process.env.ENDATA_API_KEY}`,
  } } },
));

// Every tool takes { publicationId, input } and returns JSON as text.
async function call(name, input = {}, extra = {}) {
  const result = await client.callTool({
    name,
    arguments: { publicationId, input, ...extra },
  });
  const value = JSON.parse(result.content[0].text);
  if (result.isError) throw new Error(`${name}: ${value.message}`);
  return value;
}
```

> **Pruébalo antes de escribir nada** La [página para desarrolladores](https://endata.com/es/developers#mcp-playground) tiene un área de pruebas que muestra las llamadas a las herramientas y sus respuestas, sin necesidad de clave.

## Paso 3: Encuentra las preguntas que vale la pena responder

**Llama a `questions_list` con el filtro `to-answer`, o agrega una pregunta con `question_create`.**

Una pregunta es la unidad de trabajo: algo que pregunta un cliente y para lo cual el negocio debería tener la mejor respuesta. Las preguntas llegan de las sugerencias de Endata, de las brechas de tu informe de visibilidad en IA o de ti.

```javascript
// Questions still waiting for an answer, highest priority first.
const { questions } = await call("questions_list", {
  filter: "to-answer",
  limit: 10,
});

// Or add one of your own: a gap from your AI Visibility report, say.
const added = await call("question_create", {
  text: "How much cyber insurance does a 40-person firm need?",
  customers: "Owners of professional services firms",
});
```

`questions_list` devuelve `questions`, `counts` por estado y un `summary`. Los filtros incluyen `to-answer`, `needs-update` (respondida, pero las noticias cambiaron o la respuesta quedó desactualizada), `open` y `all`. `discovery_read` da una vista más amplia: qué porcentaje de las preguntas de los clientes has respondido y qué responder a continuación.

## Paso 4: Investiga y redacta la respuesta

**Llama a `question_research` para reunir evidencia y escribir un borrador con citas.**

La investigación busca en los últimos 30 días de noticias y fuentes web para esa pregunta, conserva hasta ocho piezas de evidencia y escribe una respuesta que las cita. Se ejecuta en segundo plano y descuenta de la asignación mensual de respuestas investigadas del plan.

```javascript
// Research the question and draft its answer. This runs in the
// background and counts against the plan's monthly answers.
const question = questions[0];
await call("question_research", { questionId: question.id });

// Optional: add what only the business knows, attributed to it.
await call("question_perspective", {
  questionId: question.id,
  text: "We size cover from the client's largest single contract, not headcount.",
});
```

`question_perspective` es el paso que la mayoría de los flujos omite y no debería. Agrega la opinión propia del negocio, atribuida a un autor con nombre, que es lo que hace que la respuesta sea más que un resumen de páginas ajenas.

## Paso 5: Lee el borrador y su evidencia

**Llama a `question_read` y `answer_read`, y conserva el `draftRevision` que revisaste.**

```javascript
// When research is done ("question.researched" webhook, or poll),
// read the draft and the evidence behind it.
const detail = await call("question_read", { questionId: question.id });
const answer = await call("answer_read", { questionId: question.id });

console.log(answer.content);        // the draft
console.log(answer.pending);        // true: readers do not see it yet
console.log(answer.draftRevision);  // the exact revision you reviewed
```

Aquí es donde un agente se gana su lugar. Pídele que compare el borrador con la evidencia que devuelve `question_read`, que marque cualquier afirmación sin fuente y que guarde un borrador mejorado con `answer_update`, que recibe el contenido y el `expectedRevision` en que se basó, para que dos editores no se sobrescriban entre sí. `answer_preview` devuelve la página tal como se publicaría.

> **No consultes en bucle si puedes escuchar** Agrega un endpoint de webhook y suscríbete a `question.researched`. Los payloads traen `questionId` y `revisionId`, no el texto, así que obtén el borrador cuando llegue el evento.

## Paso 6: Publica, con una persona en el circuito

**Llama a `prepare_action`, muéstrale su resumen a una persona y luego llama a `answer_publish` con el token de confirmación.**

Publicar, despublicar, compartir y los cambios administrativos se marcan como consecuentes. Endata no deja que una clave sin supervisión los realice por defecto. Hay dos caminos, y debes elegir con criterio:

- **Confirma cada acción:** `prepare_action` devuelve un resumen y un token ligado a esa entrada exacta y al estado actual, válido por 10 minutos. Muéstrale el resumen a una persona; pasa el token cuando esté de acuerdo.
- **Otorga permisos sin supervisión:** Un propietario puede permitir explícitamente que una clave actúe sin supervisión. Úsalo para un flujo en el que confías de principio a fin, y mantén acotados los permisos de la clave.

```javascript
// Publishing is consequential. Prepare the exact action first:
const prepared = await client.callTool({
  name: "prepare_action",
  arguments: {
    publicationId,
    operation: "answer_publish",
    input: { questionId: question.id, revisionId: answer.draftRevision },
  },
});
const { confirmationToken } = JSON.parse(prepared.content[0].text);

// Show the summary to a person. Once they agree, within 10 minutes:
const live = await call(
  "answer_publish",
  { questionId: question.id, revisionId: answer.draftRevision },
  { confirmationToken, requestKey: `publish-${answer.draftRevision}` },
);
```

`requestKey` hace la llamada idempotente: un reintento con la misma clave y la misma entrada devuelve el primer resultado y no publica dos veces. La respuesta se publica al instante en `/questions/<slug>` de la publicación, y `answer.url` en el resultado es su dirección.

> **Un token no es consentimiento** `prepare_action` demuestra qué acción se preparó, no que una persona estuvo de acuerdo. Tu cliente es responsable de preguntar de verdad. No hagas que el agente prepare y confirme de un solo golpe.

## Paso 7: Comparte artículos y escucha eventos

**Usa `article_share` para publicar artículos en las redes conectadas, y webhooks para reaccionar cuando algo se publica.**

Compartir funciona con los **artículos**, las notas de noticias que Endata escribe sobre tus temas, no con las respuestas. `connections_list` devuelve las cuentas conectadas; `article_share` recibe un `articleId`, un `connectionId`, tu `commentary` y cuándo enviarlo (`now`, `at` una hora, o cuando esté `published`). Es consecuente, así que se aplica la misma regla de confirmación.

Los webhooks cierran el ciclo. Hasta 10 endpoints HTTPS por proyecto reciben eventos firmados como `question.answered`, `question.updated`, `article.approved` y `share.sent`. La entrega es al menos una vez, con ocho intentos en unas 22 horas, así que haz el receptor idempotente y verifica la firma:

```javascript
import { createHmac, timingSafeEqual } from "node:crypto";

// Pass the exact, unmodified UTF-8 request body and request headers.
function verifyWebhook(rawBody, headers, secret) {
  const timestamp = headers.get("Webhook-Timestamp");
  const signature = headers.get("Webhook-Signature");
  if (!timestamp || !/^\d+$/.test(timestamp)) return false;
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
  if (!/^v1=[a-f0-9]{64}$/.test(signature || "")) return false;

  const expected = createHmac("sha256", secret)
    .update(timestamp + "." + rawBody, "utf8")
    .digest();
  const received = Buffer.from(signature.slice(3), "hex");
  return timingSafeEqual(expected, received);
}
// After verification, parse and validate the event.
// Atomically persist it with a unique constraint on Webhook-Id.
// Return 2xx after persistence; duplicate events should also return 2xx.
// Process asynchronously and reconcile current state through the API.
```

## Deja que otros agentes lean tus respuestas

Todo lo que publicas queda disponible de inmediato para cualquier agente, sin clave y sin trabajo de integración. Cada publicación sirve un servidor MCP de solo lectura con cuatro herramientas: `search_answers`, `get_answer`, `list_questions` y `list_changes`.

```javascript
// No key. Any newsroom: yours, or one you want your agent to cite.
const newsroom = new Client({ name: "reader", version: "1.0.0" });
await newsroom.connect(new StreamableHTTPClientTransport(
  new URL("https://news.example.com/mcp"),
));
const hits = await newsroom.callTool({
  name: "search_answers",
  arguments: { q: "cyber insurance for small firms" },
});
```

El mismo contenido también se sirve como `llms.txt`, `llms-full.txt`, un JSON Feed en `/answers.json` y Markdown para cualquier respuesta, añadiendo `.md` a su dirección o enviando `Accept: text/markdown`. Este es el lado práctico de ser visible para la IA: un asistente que sale a buscar encuentra una respuesta limpia y con fuentes en el formato que mejor lee.

## ¿Prefieres REST? Las mismas operaciones están ahí

Las herramientas MCP y la API REST se generan desde un mismo registro, así que todo lo anterior se puede hacer con `POST https://app.endata.com/api/v1/publications/:id/operations/:operationId`. Las escrituras llevan el encabezado `Idempotency-Key`, y las confirmaciones se preparan en `/publications/:id/confirmations`.

- `GET /api/v1/operations` lista cada operación con su JSON Schema, sin clave.
- `GET /api/v1/openapi.json` es un documento OpenAPI 3.1 generado desde el mismo registro.
- Límites: 120 solicitudes por minuto por clave, cuerpos JSON de 1 MB (14 MB para subidas de imágenes).

No hay un SDK de Endata que instalar y no hace falta: usa el SDK de MCP o un simple `fetch`. La referencia completa está en la [página para desarrolladores](https://endata.com/es/developers).

## Lo que el servidor MCP no hace

- **No expone el informe de visibilidad en IA.** No hay una herramienta para generar uno ni para leer sus posiciones. Incorpora las brechas como preguntas con `question_create`.
- **No usa OAuth personal.** Hoy solo se aceptan claves de API del proyecto.
- **No está en Solo.** La API, MCP y los webhooks forman parte de Business y Agency.
- **No evita los límites del plan.** La investigación y la redacción descuentan de la misma asignación mensual que la app.

## Preguntas frecuentes

### ¿Cuál es la URL del servidor MCP de Endata?

`https://app.endata.com/mcp`. Es Streamable HTTP sin estado sobre POST, autenticado con una clave de API del proyecto enviada como `Authorization: Bearer fsk_…`.

### ¿Qué clientes MCP funcionan con Endata?

Cualquier cliente que admita Streamable HTTP con un encabezado bearer, incluidos Claude Code, Codex y los SDK oficiales de Model Context Protocol.

### ¿Qué plan incluye MCP y la API?

Business ($199 al mes) y Agency. Solo no incluye la API, MCP ni webhooks. Mira los [precios](https://endata.com/es/pricing).

### ¿Puede un agente publicar sin una persona?

Solo si el propietario de un espacio de trabajo le otorgó a esa clave permisos sin supervisión. De lo contrario, las herramientas consecuentes requieren un token de confirmación de `prepare_action`, que tu cliente solo debería obtener después de que una persona esté de acuerdo.

### ¿Cuántas herramientas expone el servidor?

77 operaciones más `prepare_action`, que cubren contenido publicado, artículos, publicación, investigación, preguntas, respuestas, medios, configuración, webhooks, equipo y widgets. Una clave solo ve las herramientas que sus permisos permiten.

### ¿Puedo leer mi informe de visibilidad en IA por MCP o por la API?

Hoy no. Ninguna operación expone el informe. `discovery_read` y `search_ai_read` cubren el porcentaje de preguntas respondidas, las visitas de referencia desde IA y las solicitudes de recuperación.

### ¿Hay un servidor MCP público para el contenido publicado?

Sí. Cada publicación de Endata sirve un servidor MCP de solo lectura y sin clave en `/mcp`, con `search_answers`, `get_answer`, `list_questions` y `list_changes`, que se descubre en `/.well-known/mcp.json`.

### ¿Hay un SDK o una especificación OpenAPI?

No hay un SDK específico de Endata. Hay un documento OpenAPI 3.1 en vivo en `https://app.endata.com/api/v1/openapi.json`, y el catálogo de operaciones con JSON Schemas en `/api/v1/operations`.

## Sigue leyendo

- [Referencia de API, MCP y webhooks](https://endata.com/es/developers): Cada operación, permiso y ejemplo, con un área de pruebas en vivo.
- [Cierra una brecha de visibilidad en IA en 10 minutos](https://endata.com/es/guides/fix-ai-visibility-gap): El mismo flujo, hecho a mano en la app.
- [Endata para agencias](https://endata.com/es/agencies): Un espacio de trabajo por cliente, bajo tu marca, con la API.
