Conecta tu agente de IA (MCP)
Tarno incluye un servidor MCP neutral y de solo lectura para que un agente de IA pueda consultar el corpus de marcas de INAPI a través del Model Context Protocol. Expone el mismo contrato de lectura que la API REST — respaldado por la misma capa de consultas y los mismos esquemas de Zod — de modo que los dos transportes devuelven resultados idénticos.
Endpoint y transporte
| Propiedad | Valor |
|---|---|
| Endpoint | https://mcp.tarno.cl |
| Transporte | Streamable HTTP (MCP) |
| Autenticación | Encabezado X-API-Key, enviado por solicitud |
| Identidad del servidor | tarno-read-mcp |
El servidor responde MCP JSON-RPC sobre el transporte Streamable HTTP. Una sonda GET /health es la
única ruta no autenticada; cada llamada a herramienta está autenticada.
Autenticación
La autenticación es por herramienta, no por conexión. Cada handler de herramienta verifica la clave presentada
antes de leer cualquier cosa, de modo que una clave ausente o inválida nunca devuelve datos del corpus. Envía tu
clave emitida por el operador en el encabezado X-API-Key en las solicitudes del transporte (marcador de posición <API_KEY>
en esta documentación):
X-API-Key: <API_KEY>
Ambas herramientas requieren el scope brands:read (una clave sin restricción, con scopes vacíos, también funciona) — consulta
la guía de autenticación. Una clave ausente/inválida se rechaza como un error de herramienta unauthorized;
una clave válida a la que le falta el scope se rechaza como forbidden.
El handshake
initializea nivel de transporte puede tener éxito sin clave — la invariante estricta es que una llamada a herramienta nunca devuelve datos del corpus a menos que la clave sea válida y tenga el scope. Envía siempre el encabezado.
Cuota
La misma cuota mensual que rige la API REST aplica al MCP. Cuando una clave está sobre
la cuota, el servidor responde con HTTP 429 y un encabezado Retry-After (segundos hasta el reinicio),
coincidiendo byte por byte con la respuesta de cuota de REST:
HTTP/1.1 429 Too Many Requests
Retry-After: 1209600
{ "error": { "code": "quota_exceeded", "message": "Monthly quota exceeded", "requestId": "..." } }
Catálogo de herramientas
El servidor registra sólo herramientas de lectura, y cada una es el gemelo exacto de una ruta
REST: misma validación, mismos datos, mismos códigos de error. Las dos de abajo son las de entrada;
el catálogo completo lo enumera tu cliente MCP con tools/list, e incluye entre otras
get_feriados y get_feriados_cobertura (calendario de feriados y el rango que afirma cubrir),
get_freshness, get_sync_runs, search_personas y la familia watch_* de vigilancia.
Las personas dicen qué clase de parte son, desde 2026-09-08. Cada persona —dentro de
get_brand_detail, dentro deget_brand_reporty ensearch_personas— lleva cinco campos añadidos:tipo(natural/juridica/desconocido),tipoOrigen(rut/sufijo/manual, omitido, nuncanull, cuando no hubo señal),observacion,nombrePublicadoyrevision. Son aditivos —ningún campo se quitó, se renombró ni cambió de tipo— y se leen bajo el mismo scopebrands:read, así que ninguna clave en circulación necesita re-emitirse. La paridad REST≡MCP de estos campos está verificada con un test deep-equal contra Postgres real, incluida la omisión detipoOrigen. Qué significa cada uno: búsqueda de personas.
search_brands
Busca en el corpus neutral de marcas por texto libre (full-text + fuzzy) con filtros opcionales y
paginación por keyset estable. Idéntica a REST GET /v1/brands.
Entrada (la forma de búsqueda compartida — todos los campos opcionales):
| Campo | Type | Notas |
|---|---|---|
q |
string | Consulta de texto libre. Cuando está presente, los resultados se rankean. |
clase |
integer | Clase de Niza, 1–45. |
estado |
string | Código de estado (catálogo controlado). |
tipoSigno |
string | Código de tipo de signo (catálogo controlado). |
fechaDesde |
YYYY-MM-DD |
Límite inferior de la fecha de presentación. |
fechaHasta |
YYYY-MM-DD |
Límite superior de la fecha de presentación. |
limit |
integer | Tamaño de página, por defecto 20, máximo 100. |
cursor |
string | Cursor de keyset opaco para la página siguiente. |
Salida: una página JSON de resúmenes de marcas — { items: [...], nextCursor: string | null } —
idéntica a REST GET /v1/brands. La carga útil se devuelve como el primer bloque de contenido de texto del resultado de
la herramienta (parséala como JSON).
get_brand_detail
Obtiene una marca por su número de solicitud, compuesta con sus clases, personas (con rol) y
anotaciones del Estado-Diario. Idéntica a REST GET /v1/brands/:nroSolicitud.
Entrada:
| Campo | Type | Notas |
|---|---|---|
nroSolicitud |
string | El número de solicitud de la marca (obligatorio). |
Salida: el detalle completo de la marca como JSON. Un número de solicitud desconocido devuelve un
error de herramienta estructurado not_found (ver Forma de los errores abajo), reflejando el
404 not_found del equivalente REST.
Forma de los errores
Todos los errores de herramienta comparten una sola forma: un resultado de herramienta con
isError: true cuyo texto es el JSON { "error": { "code": "<code>", "message": "<mensaje>" } } —
idéntico al envoltorio {error:{code}} que la API REST devuelve para 4xx/5xx (REST≡MCP). Un
cliente puede hacer JSON.parse(text).error.code de forma uniforme para cualquier error de
herramienta. Los code que verás:
code |
Significado |
|---|---|
unauthorized |
Clave ausente, inválida, revocada o expirada. |
forbidden |
La clave es válida pero le falta el scope requerido (p. ej. brands:read). |
invalid_input |
Entrada inválida (p. ej. la regla "exactamente uno de nroSolicitud o q"). |
not_found |
Búsqueda por id de un recurso desconocido (o de otro tenant). |
query_timeout |
La consulta excedió el presupuesto de tiempo; reintentable. |
service_unavailable |
Dependencia temporalmente no disponible; reintentable. |
fuera_de_cobertura |
Se pidió un tramo que el calendario de feriados no afirma cubrir. Único caso que además lleva coverage dentro del error, con el rango real. |
internal_error |
Error interno genérico — nunca filtra detalles internos. |
Los detalles internos de la base de datos o del transporte nunca se incluyen en el mensaje.
Conecta tu cliente de IA
Cliente MCP genérico de Streamable-HTTP
La mayoría de los clientes MCP aceptan una entrada de servidor HTTP con encabezados personalizados. Apúntalo al endpoint y
envía tu clave en el encabezado X-API-Key:
{
"mcpServers": {
"tarno": {
"type": "streamable-http",
"url": "https://mcp.tarno.cl",
"headers": { "X-API-Key": "<API_KEY>" }
}
}
}
Claude Desktop (mediante el puente mcp-remote)
Claude Desktop lanza servidores MCP sobre stdio, y su interfaz integrada de conector personalizado solo
admite servidores con OAuth o sin autenticación — no tiene un campo para un encabezado X-API-Key personalizado. Para llegar
a un endpoint autenticado por encabezado como Tarno, haz de puente con el asistente mcp-remote,
que corre localmente sobre stdio e inyecta el encabezado en cada solicitud.
Requisito previo: Node.js 18 o superior en tu PATH (Claude Desktop invoca
npx). Verifica con node --version.
1. Abre tu archivo de configuración de Claude Desktop (créalo si no existe):
| OS | Path |
|---|---|
| macOS | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Windows | %APPDATA%\Claude\claude_desktop_config.json |
También puedes llegar a él desde Settings → Developer → Edit Config.
2. Agrega Tarno a mcpServers. Mantén tu clave en una entrada env (no en línea dentro de args) — este es
el patrón seguro y evita un bug conocido de Claude Desktop/Windows donde un espacio dentro de un valor de args
se escapa mal al invocar npx:
{
"mcpServers": {
"tarno": {
"command": "npx",
"args": [
"-y", "mcp-remote",
"https://mcp.tarno.cl",
"--header", "X-API-Key:${TARNO_API_KEY}"
],
"env": {
"TARNO_API_KEY": "<API_KEY>"
}
}
}
}
Reemplaza <API_KEY> con tu clave emitida por el operador. (Como una clave de API nunca contiene espacios, la
forma en línea "--header", "X-API-Key:<API_KEY>" también funciona — pero el patrón env de arriba mantiene la
clave fuera de la lista de args y esquiva el bug del espacio.)
3. Reinicia Claude Desktop por completo (cierra y vuelve a abrir). Tarno entonces aparece como una fuente de
herramientas conectada; puedes pedirle a Claude que busque marcas u obtenga el detalle de una marca, y él llamará a
search_brands / get_brand_detail por ti.
Resolución de problemas: si el servidor no aparece, confirma que node --version funcione en una terminal,
que el JSON sea válido (sin comas finales) y que la clave sea una clave activa y con scope — un error de herramienta
unauthorized/forbidden significa que la clave está ausente, es inválida o le falta brands:read.
Para un cliente programático (connect + callTool) usando @modelcontextprotocol/sdk, consulta los
ejemplos de código.
Ver también
- Autenticación y scopes —
X-API-Key,brands:read, ciclo de vida, códigos de error. - Ejemplos de código — un cliente mínimo del SDK de MCP.
- Primeros pasos — la puesta en marcha equivalente en REST.