Saltar a contenido

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 initialize a 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 de get_brand_report y en search_personas— lleva cinco campos añadidos: tipo (natural/juridica/desconocido), tipoOrigen (rut/sufijo/manual, omitido, nunca null, cuando no hubo señal), observacion, nombrePublicado y revision. Son aditivos —ningún campo se quitó, se renombró ni cambió de tipo— y se leen bajo el mismo scope brands: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 de tipoOrigen. 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, 145.
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