Hace seis meses empezamos a estudiar el Model Context Protocol.

En ese momento, MCP estaba ganando tracción en la comunidad de desarrolladores pero se usaba principalmente para acceso a archivos locales, herramientas de código y APIs simples. Nadie lo estaba usando realmente para datos de marketing en producción — conexiones OAuth reales, datos en vivo de plataformas publicitarias, workspaces multi-cuenta. Nos pareció un espacio interesante.

Esta es la historia de lo que construimos, lo que nos sorprendió y lo que haríamos diferente.

Lo que intentábamos resolver

Detrics ya se conectaba a más de 25 plataformas de marketing — Facebook Ads, Google Ads, TikTok, Shopify, y más. Nuestros usuarios podían consultar esos datos a través de Google Sheets y Looker Studio. Pero el feedback que recibíamos constantemente era: “¿No puedo simplemente hacerle una pregunta?”

El modelo mental de consultar datos de marketing no debería requerir saber GAQL, ni armar un dashboard en Looker, ni exportar CSVs. Deberías poder decir “Compará mi ROAS de Google y Meta del mes pasado” y obtener una respuesta.

MCP ofrecía exactamente esa interfaz. Un asistente de IA que podía llamar a nuestras APIs y presentar los resultados en lenguaje natural.

Eligiendo el transporte

MCP soporta múltiples transportes. La opción obvia para un servidor remoto es SSE (Server-Sent Events), que es lo que usaban la mayoría de las implementaciones MCP alojadas al momento del lanzamiento. Pero cuando empezamos a construir, StreamableHTTP (HTTP stateless) ya había surgido como el transporte preferido para servidores remotos.

StreamableHTTP es más simple: cada request es un POST stateless, el servidor responde con JSON (o chunks en streaming para operaciones más largas), y no hay una conexión persistente que gestionar. Para un servidor de producción corriendo detrás de un load balancer, esto es mucho más fácil de operar que conexiones SSE de larga duración.

Fuimos con StreamableHTTP desde el principio y no nos arrepentimos. Los deploys son simples, el escalado horizontal funciona, y el debugging es directo.

OAuth 2.1 — la parte difícil

La complejidad real no fue el protocolo MCP en sí. Fue el flujo OAuth 2.1 que hace que los servidores MCP remotos funcionen con Claude y ChatGPT.

Cuando Claude se conecta a un servidor MCP remoto, no simplemente envía un request — primero descubre el endpoint de autorización del servidor, redirige al usuario para que se autentique, intercambia un código por un token, y luego usa ese token para los requests MCP subsiguientes. Esto es OAuth 2.1 estándar con PKCE, pero hay varios requisitos específicos de MCP que no siempre son obvios:

RFC 9728: OAuth Protected Resource Metadata

Antes de hacer cualquier cosa, los clientes MCP buscan /.well-known/oauth-protected-resource para descubrir la URL del servidor de autorización. También intentan una variante específica por path: /.well-known/oauth-protected-resource/mcp.

Inicialmente solo teníamos el path base registrado. Claude intentaba la variante específica primero, recibía un 404, y fallaba. Agregar esa segunda ruta lo solucionó.

// Ambas rutas necesitan el mismo handler
router.get("/.well-known/oauth-protected-resource", oauthProtectedResourceHandler);
router.get("/.well-known/oauth-protected-resource/mcp", oauthProtectedResourceHandler);

Header WWW-Authenticate en 401

Cuando los clientes MCP reciben una respuesta 401 Unauthorized, miran el header WWW-Authenticate para saber dónde autenticarse. Sin él, no tienen idea de dónde redirigir al usuario.

WWW-Authenticate: Bearer realm="Detrics", resource_metadata="https://mcp.detrics.io/.well-known/oauth-protected-resource"

No incluir este header causaba fallas silenciosas — los clientes recibían 401s y no sabían qué hacer.

Path raíz vs. path /mcp

Esto nos sorprendió. Después de que el flujo OAuth se completa, Claude envía el primer request MCP a la URL base del servidor de autorización, no a un path como /mcp. Entonces si tu URL de conector es https://mcp.detrics.io, Claude envía POST / — no POST /mcp.

Teníamos nuestro handler MCP montado en /mcp. La solución fue una regla de rewrite en Nginx que redirige los requests al path raíz hacia el handler MCP. Y la implicación es que la URL del conector que los usuarios ingresan debe ser la URL base limpia (https://mcp.detrics.io), no https://mcp.detrics.io/mcp.

Esto es en realidad más intuitivo para los usuarios — es consistente con cómo Slack, Linear y otros servidores MCP exponen sus endpoints. Pero tomó algo de debugging descubrirlo.

La función getBaseUrl()

Nuestro servidor corre detrás de un reverse proxy Nginx. Los endpoints de metadata MCP (como el documento de OAuth protected resource) necesitan devolver la URL pública del servidor, no localhost:3000.

Construimos un helper pequeño que lee los headers X-Forwarded-Host y X-Forwarded-Proto configurados por Nginx:

function getBaseUrl(req: Request): string {
  const host = req.headers["x-forwarded-host"] || req.headers["host"];
  const proto = req.headers["x-forwarded-proto"] || "https";
  return `${proto}://${host}`;
}

Lo crítico: Nginx debe configurar estos headers correctamente. Sin proxy_set_header X-Forwarded-Host $host, el servidor devuelve localhost:3000 en su metadata, lo que causa que los clientes OAuth intenten alcanzar la URL incorrecta.

AI Contexts: el insight de producto

Desde una perspectiva puramente MCP, el servidor es un wrapper de API con autenticación. Lo que lo hizo realmente útil fue el concepto de AI Contexts.

El problema con las consultas crudas de datos de marketing es la especificidad. Para consultar datos de Facebook Ads, necesitás especificar un identificador de plataforma (facebook_ads), un ID de cuenta (un número de 16 dígitos), métricas, dimensiones y un rango de fechas. Es mucha información para un prompt conversacional.

Los AI Contexts son configuraciones de consulta guardadas — elegís tus plataformas y cuentas una vez, le ponés un nombre al Context, y después tu asistente de IA puede referenciarlo por nombre. El servidor MCP los almacena en tu workspace de Detrics y resuelve la configuración completa cuando se ejecuta una consulta.

Desde la perspectiva del usuario:

“Mostrá el reporte de rendimiento semanal”

reemplaza:

“Consultá facebook_ads para la cuenta 1234567890, mostrá inversión y ROAS de los últimos 7 días. También consultá google_ads para la cuenta 9876543210 con las mismas métricas.”

Este es el insight clave: el problema difícil del acceso conversacional a datos no es la ejecución de la consulta, es reducir la fricción de especificar el contexto. Los AI Contexts resuelven eso.

Plantillas de prompts: reduciendo el síndrome de la página en blanco

El otro insight de producto fue que los usuarios muchas veces no sabían cómo formular sus preguntas. “¡Preguntá lo que quieras!” no es una experiencia de onboarding útil.

Construimos una biblioteca de más de 40 plantillas de prompts — prompts pre-escritos para las tareas de análisis más comunes. El valor de marketing es obvio (SEO, contenido), pero el valor de producto es más importante: las plantillas enseñan a los usuarios el lenguaje de las consultas MCP. Una vez que alguien usó algunas plantillas, empieza a escribir sus propias variaciones naturalmente.

Las plantillas se sirven desde la web app de Detrics en /mcp/templates. Los usuarios copian un prompt, lo pegan en Claude o ChatGPT, y personalizan desde ahí.

Subdominio dedicado: mcp.detrics.io

Inicialmente alojamos MCP en oauthdev.detrics.io/mcp — simplemente agregado a un servidor existente. Cuando decidimos lanzarlo en serio, lo movimos a un subdominio dedicado: mcp.detrics.io.

Las razones:

  1. Identidad clara. mcp.detrics.io es inequívoco — es el servidor MCP de Detrics.
  2. Consistente con el ecosistema. La mayoría de los servidores MCP de producción usan un subdominio limpio (mcp.slack.com, mcp.linear.app, etc.).
  3. Independencia operacional. El servidor MCP puede escalar independientemente de la API principal.

Configurarlo requirió registros DNS, configuración de virtual host en Nginx y certificados SSL via Certbot. Todo el proceso tomó aproximadamente una hora.

Qué haríamos diferente

Empezar con un subdominio dedicado. Perdimos tiempo debuggeando problemas de URLs que surgieron de tener MCP montado en un path de un servidor compartido. Empezar con mcp.tuproducto.com desde el día uno evita la confusión.

Agregar la ruta well-known específica por path temprano. La spec permite a los clientes intentar tanto /.well-known/oauth-protected-resource como /.well-known/oauth-protected-resource/mcp. Implementá ambas desde el inicio.

Testear con múltiples clientes. Claude y ChatGPT implementan la spec MCP de manera ligeramente diferente. Algo que funciona en Claude puede fallar en ChatGPT (y viceversa). Testeá ambos temprano.

El header WWW-Authenticate no es opcional. Incluso si implementás todo lo demás correctamente, no incluir este header causa fallas silenciosas de 401 que son difíciles de debuggear. Agregalo desde el día uno.

Dónde estamos ahora

El servidor MCP de Detrics está corriendo en producción en mcp.detrics.io. Soporta Claude, ChatGPT, Claude Code, Gemini CLI y Codex. Se conecta a más de 25 plataformas de marketing, soporta AI Contexts e incluye más de 40 plantillas de prompts.

Si querés probarlo, podés conectarte desde app.detrics.io/mcp — toda la configuración toma menos de 5 minutos.

Si estás construyendo tu propio servidor MCP y tenés preguntas sobre algo de lo que cubrimos acá, escribinos a support.detrics.io. Estamos felices de compartir más detalles.