TL;DR
- Hacer “públicos” los datos de una app no es lo mismo que volcar tu base de datos en un vector store. Es una allowlist deliberada de documentos, catálogos, registros de cambios, páginas de precios y APIs de lectura con alcance limitado en los que agentes y personas pueden confiar.
- El patrón de producción que funciona en 2026 tiene tres capas: contenido estático fácil de descubrir (
llms.txt, markdown, sitemaps), un servidor MCP para recursos estructurados y herramientas de alcance limitado, y un servicio RAG para búsqueda semántica sobre el mismo corpus público. - La seguridad viene de la separación: una ruta de lectura pública, una ruta de escritura autenticada, scopes por herramienta y filtros de recuperación que nunca acceden a filas privadas. OAuth 2.1 es para endpoints MCP protegidos, no para todo.
- El control de costos combina varias medidas, no un solo truco: guarda en caché los embeddings y los conjuntos de recuperación, usa la caché de prompts del proveedor para prompts de sistema estables, aplica caché semántica a preguntas frecuentes, enruta consultas sencillas a modelos más pequeños y limita el tamaño del contexto.
- MCP avanza hacia un mejor soporte nativo de caché (
ttlMs,cacheScopeen el release candidate del 2026-07-28). Planifica el uso de transporte HTTP Streamable, servidores sin estado y evals antes de considerar que el sistema está listo para producción. - Si ya conoces la infraestructura de sitios web preparada para agentes y los fundamentos de diseño de RAG, este artículo conecta ambos temas: cómo ofrecer el conocimiento público de tu app como una superficie de producto segura y económica para agentes.
Qué aprenderás aquí
- Qué deberían entender los PMs e ingenieros por “datos públicos de una app”
- Una arquitectura de referencia para MCP + RAG sobre un corpus público
- Cómo establecer el límite de seguridad entre lecturas públicas y escrituras privadas
- Decisiones de diseño de un servidor MCP: recursos frente a herramientas, autenticación, caché y tarjetas de servidor
- Patrones de RAG que siguen siendo seguros, rápidos y económicos a escala
- Un ejemplo concreto de asistente para documentación pública con fragmentos de código
- Una lista de verificación para producción que puedes usar antes del lanzamiento
Estructura propuesta del artículo
Este artículo asume que quieres exponer el conocimiento del producto a agentes y usuarios externos sin abrir todo tu backend. Las siguientes secciones avanzan desde el enfoque de producto → arquitectura → seguridad → MCP → RAG → ejemplo → lista de verificación. Si tu objetivo es únicamente un RAG interno para empleados, omite las secciones sobre la allowlist pública y conserva las recomendaciones de producción para MCP/RAG.
La pregunta de producto: ¿qué debería ser público?
Antes de MCP o RAG, responde una pregunta de producto:
¿Qué partes de los datos de nuestra app ayudan a usuarios y agentes a tomar mejores decisiones cuando se comparten abiertamente?
Buenos candidatos para ser públicos:
- documentación del producto, referencias de API, guías de SDK
- páginas de precios, límites de planes, matrices de funcionalidades
- registros públicos de cambios, notas de versión, páginas de estado
- catálogos abiertos: integraciones, plantillas, conjuntos de datos públicos, publicaciones de marketplace
- artículos de soporte marcados para consumo público
- APIs de lectura con alcance limitado: “buscar documentación pública”, “obtener límites de planes”, “listar integraciones públicas”
Malos candidatos para ser públicos:
- registros de clientes, historial de facturación, tickets de soporte con PII
- runbooks internos, notas de incidentes, directorios de empleados
- exportaciones sin procesar de bases de datos “porque los embeddings necesitan texto”
- herramientas de administración, APIs de escritura o cualquier cosa que modifique el estado sin autenticación robusta
Usa un filtro sencillo:
| Pregunta | Público | Privado |
|---|---|---|
| ¿Publicaríamos esto en nuestro sitio de marketing? | Por lo general, sí | — |
| ¿Contiene datos específicos de un usuario o tenant? | — | Sí |
| ¿Podría un agente interpretar esto como permiso para actuar? | Rediseñar la superficie | — |
| ¿Queda desactualizado en cuestión de horas? | Necesita un pipeline de actualización | — |
| ¿Los equipos de ventas o legal ya aprobaron que se comparta externamente? | Buena señal | Revisar |
Mi opinión editorial: la mayoría de los equipos falla aquí al indexar todo lo que se puede buscar en lugar de definir un corpus público con responsables, TTLs y reglas de revisión.
Tres capas, un corpus público
Piensa en tres capas que comparten una única fuente de referencia incluida en una allowlist:
Layer 1: Discoverable Content
llms.txt, markdown pages, sitemap, /openapi or API catalog
-> passive reading for crawlers and agents
Layer 2: MCP Server
resources (read structured public data)
tools (bounded queries: search_docs, get_pricing, list_integrations)
-> active capability discovery and tool calls
Layer 3: RAG Service
hybrid retrieval + rerank + citations over the same public index
-> semantic answers with evidence and refusal behavior
¿Por qué tres capas en lugar de una?
- Contenido estático es la superficie más económica. Los agentes pueden leerlo sin que tu infraestructura ejecute un modelo.
- MCP proporciona a los clientes host una forma estándar de descubrir e invocar capacidades. La especificación de MCP define servidores que exponen recursos, prompts y herramientas mediante JSON-RPC.
- RAG ayuda cuando los usuarios hacen preguntas en lenguaje natural que abarcan muchas páginas, necesitan ordenar resultados por relevancia o requieren respuestas sintetizadas con citas.
El error es construir una sola capa. La documentación por sí sola es difícil de consultar. RAG por sí solo es difícil de descubrir y auditar. MCP por sí solo no reemplaza la calidad de búsqueda necesaria para preguntas imprecisas.
+------------------+
| Public corpus |
| (allowlisted) |
+--------+---------+
|
+-----------------+-----------------+
| | |
v v v
+-------------+ +-------------+ +-------------+
| Static web | | MCP server | | RAG index |
| llms.txt | | resources | | chunks + |
| *.md pages | | tools | | metadata |
+------+------+ +------+------+ +------+------+
| | |
v v v
Crawlers / Agent hosts / Your app chat /
research agents Claude, Cursor support bot
Para conocer los fundamentos de descubrimiento, consulta Infraestructura preparada para agentes. Este artículo se centra en los datos de la app una vez que aceptas que los agentes leerán e invocarán tu producto.
Arquitectura de referencia
Esta es una configuración inicial orientada a producción para un producto SaaS que expone conocimiento público:
Public sources Ingestion Serving
------------- -------- -------
/docs/*.md -----> Normalize + frontmatter ---> Static CDN
/api/openapi.yaml Extract stable IDs llms.txt
/pricing.json Chunk + hash markdown routes
/changelog/*.md Embed changed chunks only MCP HTTP server
/public/catalog.json Metadata: product, version RAG API
Freshness timestamps Search UI
+-------- cache tier ---------+
| embedding cache |
| retrieval-set cache |
| semantic Q->docs cache |
| provider prompt cache |
+-----------------------------+
+-------- safety tier --------+
| public allowlist only |
| auth on write tools |
| scope checks per tool |
| evals + refusal tests |
+-----------------------------+
Reglas de diseño:
- Una allowlist, muchas superficies. No mantengas por separado la “documentación del sitio web” y la “documentación para RAG” si van a terminar desincronizadas.
- Procesamiento detrás de un gateway. El navegador, el host de agentes y el cliente MCP acceden a tu capa de API, no directamente a tu base de datos.
- Separa las herramientas MCP de lectura y escritura. Las lecturas públicas pueden no requerir autenticación o tener límites de tasa poco restrictivos. Las escrituras requieren OAuth y scopes por herramienta.
- Mide toda la cadena. El recall de recuperación y la calidad de las citas importan tanto como la fluidez de las respuestas. Consulta Apps RAG en la práctica.
Seguridad: público por diseño, no por accidente
“Público” es una propiedad de seguridad. Trátalo como tal.
1. Crea una allowlist pública, no una denylist privada
La ingesta debe leer de rutas o tablas explícitas:
/content/public/**
/openapi/public.yaml
/pricing/plans.public.json
Nunca apuntes el indexador a réplicas de la base de datos de producción, a menos que las filas se filtren previamente mediante un proceso de exportación pública.
2. Separa los recursos y las herramientas MCP según su riesgo
| Superficie | Adecuada para | Autenticación |
|---|---|---|
resources/public/* | registros de cambios, páginas de políticas, catálogos estáticos | a menudo ninguna |
tools/search_public_docs | búsqueda de alcance limitado sobre el índice público | límite de tasa opcional |
tools/get_plan_limits | datos estructurados del producto | opcional |
tools/create_support_ticket | escritura de datos de usuario | OAuth + scopes |
El tutorial de autorización de MCP es explícito: la autorización protege recursos y operaciones sensibles. La autorización es opcional en MCP, pero si tu servidor maneja datos de usuarios o acciones administrativas, usa OAuth 2.1 con HTTPS en producción.
Para endpoints protegidos, los servidores MCP deberían implementar OAuth 2.0 Protected Resource Metadata en /.well-known/oauth-protected-resource, y los clientes descubren el servidor de autorización a partir de ese documento. Aplica los scopes a nivel de herramienta, no solo en la entrada del servidor. Consulta Cómo construir un servidor MCP con inicio de sesión de Auth0 en Go y OpenFGA para permisos granulares para profundizar en el modelado de autorización.
3. Filtra antes de la recuperación, no después de la generación
Si un chunk no debe ser público, no debe convertirse en un embedding.
Bad: retrieve top-k -> prompt "ignore private data"
Good: metadata.is_public = true filter -> retrieve -> generate
Para espacios de trabajo mixtos, usa autorización a nivel de objeto en la ruta de recuperación. Las verificaciones con OpenFGA o un equivalente deben ocurrir antes de que los chunks entren en el contexto del modelo.
4. Agrega requisitos para rechazar respuestas y proporcionar procedencia
Un RAG público debería:
- citar IDs y URLs estables de las fuentes
- rechazar la respuesta cuando falte evidencia
- dar preferencia a la documentación exacta para datos de precios, límites y cumplimiento
- identificar claramente la síntesis cuando combine varias páginas
Benchmarks como CRAG y RGB siguen mostrando que un RAG básico mejora las respuestas, pero todavía falla ante el ruido, los datos desactualizados y las situaciones en las que debería decir “no lo sé”. Crea evals para esos casos antes del lanzamiento.
5. Limita la tasa y monitorea patrones de exfiltración
Los endpoints públicos serán objeto de scraping. Planifica:
- límites de tasa por IP y por token
- alertas de anomalías ante consultas de enumeración amplias
- registro de llamadas a herramientas sin registrar secretos ni cuerpos de JWT
- claves de caché que no filtren identificadores de tenants en entradas de caché pública compartida
Construcción del corpus público
Un RAG de producción comienza con disciplina en la ingesta.
IDs y metadatos estables
Cada documento público debería incluir:
id: docs/api/authentication
source_url: https://example.com/docs/api/authentication.md
product: platform
visibility: public
version: 2026-06-01
updated_at: 2026-06-28T10:00:00Z
content_hash: sha256:...
Los IDs estables hacen posibles las citas, los conjuntos de datos para evals y la invalidación de caché.
Divide en chunks sin perder la estructura
No elimines la estructura de tablas, bloques de código ni jerarquías de políticas. Prefiere:
- chunks padre/hijo para documentos largos
- divisiones que respeten las secciones
- metadatos para la ruta de encabezados (
h1 > h2 > h3) - chunks separados para tablas de precios y límites
Esto sigue las recomendaciones de Apps RAG en la práctica: conserva la estructura del conocimiento sobre el que realmente preguntan los usuarios.
Vuelve a generar embeddings solo cuando cambie el contenido
Calcula un hash de cada chunk durante la ingesta. Si content_hash no cambió, omite las llamadas para generar embeddings. A escala, esta es una de las mejoras más económicas del pipeline.
Niveles de vigencia
No todos los datos públicos se desactualizan al mismo ritmo:
| Nivel | Ejemplos | Estrategia de actualización |
|---|---|---|
| Estático | guías, conceptos | reconstruir al publicar |
| Semidinámico | precios, límites | sincronización programada + revisión manual |
| Dinámico | estado, notas de versión | webhook o caché con TTL corto |
Expón la vigencia en los metadatos de los recursos MCP y en las respuestas de RAG cuando la respuesta dependa de datos sensibles al tiempo.
Diseño de un servidor MCP para producción
MCP es el contrato entre tu app y hosts de agentes como Claude, Cursor, ChatGPT y VS Code.
Recursos frente a herramientas
Usa recursos cuando el cliente deba leer contexto público estructurado:
public://docs/getting-startedpublic://pricing/planspublic://changelog/2026-06-30
Usa herramientas cuando el agente deba invocar una operación de alcance limitado:
search_public_docs(query, product, limit)get_integration(slug)list_public_templates(category)
Mantén acotadas las entradas de las herramientas. Prefiere salidas estructuradas con IDs de fuentes en lugar de prosa libre.
Tarjetas de servidor y descubrimiento
Publica una tarjeta de servidor MCP legible por máquina y enlázala desde llms.txt o el pie de página de tu documentación. Hoy pocos productos hacen esto, y precisamente por eso quienes lo adopten temprano pueden ganar distribución en hosts de agentes. Los patrones de descubrimiento se explican en Infraestructura preparada para agentes.
Transporte y despliegue
Para servidores públicos remotos:
- prefiere el transporte HTTP Streamable en producción
- mantén el servidor MCP sin estado; pasa IDs explícitos en los argumentos de las herramientas
- colócalo detrás de un proxy inverso con TLS, verificaciones de estado y tiempos de espera para las solicitudes
- separa el servidor de autorización OAuth del servidor de recursos MCP
El release candidate de la especificación de MCP del 2026-07-28, cerrado el 21 de mayo de 2026, orienta el protocolo principal hacia HTTP sin estado y agrega indicaciones de caché estandarizadas (ttlMs, cacheScope) en los resultados de listado y lectura. La publicación final está prevista para el 28 de julio de 2026. Si empiezas ahora, diseña handlers sin estado y encabezados de caché explícitos para no tener que reconstruir cuando los clientes adopten la nueva versión.
Ejemplo: esquema mínimo de una herramienta MCP pública
{
"name": "search_public_docs",
"description": "Search publicly available product documentation. Returns snippets and source URLs only.",
"inputSchema": {
"type": "object",
"properties": {
"query": { "type": "string", "minLength": 2, "maxLength": 200 },
"product": { "type": "string", "enum": ["platform", "sdk", "cli"] },
"limit": { "type": "integer", "minimum": 1, "maximum": 5, "default": 3 }
},
"required": ["query"]
}
}
La implementación debería llamar a tu servicio de recuperación RAG o a tu índice de búsqueda, no ejecutar un LLM dentro del handler de la herramienta en cada llamada.
Capa RAG: segura, optimizada, con caché y económica
RAG sobre datos públicos sigue necesitando ingeniería para producción.
Pipeline de recuperación
Una configuración inicial sólida para conocimiento público del producto:
User question
|
v
Query rewrite (optional, small model)
|
v
Hybrid retrieval: BM25 + vector + metadata filters
|
v
Rerank top 20 -> keep top 3-5
|
v
Answer with citations + freshness note
|
v
Post-checks: grounding, policy, max tokens
Mantén pequeño el contexto. Muchos equipos recuperan diez chunks “por seguridad” y pagan por el ruido. Para documentación pública, entre tres y cinco buenos chunks suelen superar a diez mediocres.
Usa caché en cuatro niveles
Piensa más allá de la caché de prompts del proveedor:
L1 CDN / HTTP cache static docs, llms.txt, MCP resource bodies
L2 Embedding cache query/text -> vector
L3 Retrieval-set cache query embedding -> chunk IDs + scores
L4 Semantic answer cache similar question -> prior grounded answer
La caché de prompts del proveedor reduce el costo de repetir prompts de sistema largos y contexto recuperado estable en las APIs que la admiten. La caché semántica reduce las llamadas completas al LLM cuando las preguntas se repiten con distintas formulaciones. GPTCache es un patrón de referencia de código abierto para caché semántica de LLM; en producción, muchos equipos usan Redis, pgvector o su vector store actual para buscar por similitud.
Una nota práctica basada en implementaciones reales: guarda en caché resultados de recuperación o paquetes de respuestas fundamentadas (respuesta + IDs de fuentes), no solo el texto sin procesar del modelo, si usas una temperatura distinta de cero y quieres citas consistentes.
Define los umbrales de similitud de forma deliberada. Los asistentes de documentación pública suelen usar una similitud coseno de alrededor de 0.90–0.94 para aciertos de caché semántica, pero valídala con tus propios registros de consultas. Los umbrales más bajos ahorran dinero y aumentan el riesgo de respuestas desactualizadas o incorrectas.
Controles de costos que realmente se implementan
| Control | Qué ahorra | Consideración |
|---|---|---|
| Documentación pública estática | elimina las llamadas al LLM para muchas lecturas | sigue necesitando disciplina de actualización |
| Caché de conjuntos de recuperación | embeddings, búsqueda vectorial, reranker | invalidar cuando cambie el corpus |
| Caché de prompts | tokens de entrada repetidos | agrupar primero el prefijo estable |
| Enrutamiento a modelos pequeños | costo de generación en consultas sencillas | necesita verificaciones de paridad con evals |
| Límites de tokens | costo de salida y contexto | puede reducir la integridad de la respuesta |
| Indexación por lotes | gasto en embeddings durante las reconstrucciones | no sirve para consultas en línea |
Mi opinión práctica: los equipos que solo optimizan la elección del modelo sin guardar en caché la ruta de recuperación suelen dejar pasar la mitad del ahorro posible.
Evals antes de declarar que está “listo para producción”
Conjunto mínimo de evals para un RAG público:
- 50–100 preguntas reales de usuarios
- 20 casos negativos en los que debe rechazar la respuesta
- 20 casos sensibles a la vigencia de los datos (precios, límites, deprecaciones)
- métricas por componente: recall de recuperación@k, exactitud de las citas, fundamentación, latencia, costo por respuesta
Si expones el mismo corpus mediante herramientas MCP, agrega pruebas a nivel de herramienta:
- validación del esquema de la herramienta
- aplicación de scopes para herramientas protegidas
- las herramientas de búsqueda deterministas devuelven los mismos IDs para la misma consulta
- comportamiento ante límites de tasa y tiempos de espera
Ejemplo: asistente de documentación pública del producto
Esta es una estructura compacta de extremo a extremo que usa contenido estático al estilo de Astro junto con una ruta de servidor MCP/RAG.
1. Publica el corpus público
content/public/
docs/
getting-started.md
authentication.md
pricing/plans.json
changelog/2026-06-30.md
public/
llms.txt
openapi/public-api.yaml
Tu sitio estático sirve markdown y llms.txt. El proceso de ingesta replica los mismos archivos en el índice vectorial.
2. Realiza la ingesta con hashes
# ingestion/public_index.py
import hashlib
from dataclasses import dataclass
@dataclass
class PublicChunk:
id: str
text: str
source_url: str
metadata: dict
content_hash: str
def hash_text(text: str) -> str:
return hashlib.sha256(text.encode("utf-8")).hexdigest()
def upsert_chunk(store, chunk: PublicChunk) -> None:
existing = store.get_hash(chunk.id)
if existing == chunk.content_hash:
return # skip re-embed
vector = embed(chunk.text)
store.save(chunk, vector)
3. Expón una búsqueda MCP que reutilice la recuperación
# mcp/public_server.py
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("Public Docs")
@mcp.tool()
def search_public_docs(query: str, product: str = "platform", limit: int = 3):
results = retrieval.search(
query=query,
filters={"visibility": "public", "product": product},
limit=min(limit, 5),
)
return {
"results": [
{
"id": r.id,
"title": r.title,
"url": r.source_url,
"snippet": r.snippet,
"updated_at": r.updated_at,
}
for r in results
]
}
4. Ruta de respuesta RAG con caché de conjuntos de recuperación
# rag/answer.py
def answer_public_question(question: str) -> dict:
cache_key = semantic_key(question)
cached = retrieval_cache.get(cache_key)
if cached:
chunks = cached
else:
chunks = retrieval.search(
query=question,
filters={"visibility": "public"},
limit=4,
)
retrieval_cache.set(cache_key, chunks, ttl_seconds=900)
if not chunks:
return {"answer": "I could not find public documentation for that.", "sources": []}
response = llm.generate(
system=PUBLIC_DOCS_SYSTEM_PROMPT,
context=format_chunks(chunks),
question=question,
max_output_tokens=300,
)
return {
"answer": response.text,
"sources": [{"id": c.id, "url": c.source_url} for c in chunks],
}
5. Flujo de la solicitud
Agent host
|
|-- reads llms.txt + docs/*.md (free, cacheable)
|
|-- calls MCP tool search_public_docs
| -> retrieval-set cache
| -> hybrid search
|
'-- asks your RAG API for a synthesized answer
-> retrieval-set cache
-> rerank
-> small/large model route
-> citations
Esto mantiene un único índice público detrás de MCP y RAG, mientras permite que los agentes sencillos usen solo documentación estática o herramientas.
Lista de verificación para producción
Úsala antes de declarar que el sistema está listo para producción.
Producto / gobernanza de datos
- Corpus público definido con responsables identificados
- Revisión de legal y ventas para contenido sobre precios, cumplimiento y socios
- Niveles de vigencia documentados
- Ejemplos de lo que “no es público” documentados para soporte e ingeniería
Seguridad
- Allowlist pública aplicada en la ingesta y la recuperación
- OAuth 2.1 en herramientas protegidas, HTTPS en todas partes en producción
- Scopes aplicados a nivel de herramienta
- Sin secretos, tokens ni URLs privadas en logs, prompts o cachés
- Límites de tasa y monitoreo de abuso habilitados
MCP
- Recursos y herramientas separados según su riesgo
- Tarjeta de servidor publicada y enlazada desde la documentación
- Salidas estructuradas de herramientas con IDs estables
- Verificaciones de estado y tiempos de espera configurados
- Encabezados de caché o política de
ttlMsdocumentados para endpoints de listado y lectura
RAG
- Recuperación híbrida + filtros de metadatos
- Hashes de chunks para evitar volver a generar embeddings innecesariamente
- Caché de conjuntos de recuperación y umbrales de caché semántica validados
- Caché de prompts del proveedor habilitada donde se admita
- El conjunto de evals cubre el rechazo de respuestas, la vigencia de los datos y la exactitud de las citas
- Costo por respuesta y latencia p95 monitoreados
Preparación operativa
- Runbook de reindexación para publicaciones de documentación
- Invalidación de caché vinculada a la versión del corpus
- Dashboards para tasa de aciertos, tasa de errores, gasto y recall de recuperación
- Playbooks de incidentes para respuestas con precios o políticas desactualizados
Qué no debes prometer de más
Una perspectiva equilibrada es importante para PMs e ingenieros:
- MCP público más RAG no reemplaza las APIs de producto autenticadas para el estado específico de cada cliente.
- La caché semántica reduce costos a cambio de riesgo de desactualización; ajusta los umbrales y TTLs de forma explícita.
- El soporte de los hosts MCP varía según el cliente, el transporte y el flujo de autenticación. Prueba con los hosts que tus usuarios realmente usan.
- Al 30 de junio de 2026, los cambios de MCP del 2026-07-28 siguen en proceso de validación del release candidate. Construye servidores sin estado desde ahora, pero fija las pruebas de compatibilidad a la versión de la especificación que tengas como objetivo.
Fuentes
- Especificación de Model Context Protocol (2025-11-25) — protocolo base de MCP, recursos, herramientas, prompts
- Especificación de autorización de MCP — OAuth 2.1, Protected Resource Metadata, manejo de scopes
- Cómo entender la autorización en MCP — guía de OAuth orientada a producción
- El release candidate de la especificación de MCP del 2026-07-28 — HTTP sin estado, indicaciones de caché (
ttlMs,cacheScope); cerrado el 21 de mayo de 2026 - GPTCache: una caché semántica de código abierto para aplicaciones con LLM — patrón de caché semántica para apps con LLM
- Benchmarks CRAG y RGB — resumidos en Apps RAG en la práctica
- Guías internas relacionadas:
- Infraestructura preparada para agentes: llms.txt, MCP y robots.txt para IA
- Apps RAG en la práctica: conocimiento estructurado, mejor recuperación y evals reales
- Cómo construir un servidor MCP con inicio de sesión de Auth0 en Go
- OpenFGA para permisos granulares en apps modernas, MCP y flujos de trabajo de agentes