Skip to content

Connect your AI agent (MCP)

Tarno ships a neutral, read-only MCP server so an AI agent can query the INAPI trademark corpus through the Model Context Protocol. It exposes the same read contract as the REST API — backed by the same query layer and the same Zod schemas — so the two transports return identical results.

Endpoint and transport

Property Value
Endpoint https://mcp.tarno.cl
Transport Streamable HTTP (MCP)
Auth X-API-Key header, sent per request
Server identity tarno-read-mcp

The server answers MCP JSON-RPC over the Streamable HTTP transport. A GET /health probe is the only unauthenticated route; every tool call is authenticated.

Authentication

Authentication is per tool, not per connection. Each tool handler verifies the presented key before it reads anything, so a missing or invalid key never returns corpus data. Send your operator-issued key in the X-API-Key header on the transport's requests (placeholder <API_KEY> in these docs):

X-API-Key: <API_KEY>

Both tools require the brands:read scope (an unrestricted, empty-scope key also works) — see the auth guide. A key that is missing/invalid is rejected as an unauthorized tool error; a valid key lacking the scope is rejected as forbidden.

The transport-level initialize handshake may succeed without a key — the hard invariant is that a tool call never returns corpus data unless the key is valid and scoped. Always send the header.

Quota

The same monthly quota that governs the REST API applies to the MCP. When a key is over quota the server responds with HTTP 429 and a Retry-After header (seconds until reset), byte-for-byte matching the REST quota response:

HTTP/1.1 429 Too Many Requests
Retry-After: 1209600

{ "error": { "code": "quota_exceeded", "message": "Monthly quota exceeded", "requestId": "..." } }

Tool catalog

The server registers read-only tools only, each the exact twin of a REST route: same validation, same data, same error codes. The two below are the entry points; your MCP client enumerates the full catalogue with tools/list, which includes among others get_feriados and get_feriados_cobertura (the holiday calendar and the range it claims to cover), get_freshness, get_sync_runs, search_personas and the watch_* watchlist family.

People say what KIND of party they are, since 2026-09-08. Every person — inside get_brand_detail, inside get_brand_report and in search_personas — carries five added fields: tipo (natural/juridica/desconocido), tipoOrigen (rut/sufijo/manual, omitted, never null, when there was no signal), observacion, nombrePublicado and revision. They are additive — no field was removed, renamed or re-typed — and they are read under the same brands:read scope, so no key in circulation needs re-minting. REST≡MCP parity for these fields is verified by a deep-equal test against a real Postgres, including the omission of tipoOrigen. What each one means: people search.

search_brands

Search the neutral brand corpus by free text (full-text + fuzzy) with optional filters and stable keyset pagination. Identical to REST GET /v1/brands.

Input (the shared search shape — all fields optional):

Field Type Notes
q string Free-text query. When present, results are ranked.
clase integer Niza class, 145.
estado string Status code (controlled catalog).
tipoSigno string Sign-type code (controlled catalog).
fechaDesde YYYY-MM-DD Filing date lower bound.
fechaHasta YYYY-MM-DD Filing date upper bound.
limit integer Page size, default 20, max 100.
cursor string Opaque keyset cursor for the next page.

Output: a JSON page of brand summaries — { items: [...], nextCursor: string | null } — identical to REST GET /v1/brands. The payload is returned as the tool result's first text content block (parse it as JSON).

get_brand_detail

Fetch one brand by its application number, composed with its classes, persons (with role), and Estado-Diario annotations. Identical to REST GET /v1/brands/:nroSolicitud.

Input:

Field Type Notes
nroSolicitud string The brand application number (required).

Output: the full brand detail as JSON. An unknown application number returns a structured not_found tool error (see Error shape below), mirroring the REST equivalent's 404 not_found.

Error shape

Every tool error shares one shape: a tool result with isError: true whose text is the JSON { "error": { "code": "<code>", "message": "<message>" } } — identical to the {error:{code}} envelope the REST API returns for 4xx/5xx (REST≡MCP). A client can JSON.parse(text).error.code uniformly for any tool error. The codes you may see:

code Meaning
unauthorized Missing, invalid, revoked or expired key.
forbidden Valid key lacking the required scope (e.g. brands:read).
invalid_input Invalid input (e.g. the "exactly one of nroSolicitud or q" rule).
not_found By-id lookup of an unknown (or another tenant's) resource.
query_timeout The query exceeded the time budget; retryable.
service_unavailable Dependency temporarily unavailable; retryable.
fuera_de_cobertura A range was requested that the holiday calendar does not claim to cover. The only code that also carries coverage inside the error, with the real range.
internal_error Generic internal error — never leaks internal details.

Internal database or transport details are never included in the message.

Connect your AI client

Generic Streamable-HTTP MCP client

Most MCP clients accept an HTTP server entry with custom headers. Point it at the endpoint and send your key in the X-API-Key header:

{
  "mcpServers": {
    "tarno": {
      "type": "streamable-http",
      "url": "https://mcp.tarno.cl",
      "headers": { "X-API-Key": "<API_KEY>" }
    }
  }
}

Claude Desktop (via the mcp-remote bridge)

Claude Desktop launches MCP servers over stdio, and its built-in custom connector UI only supports OAuth or no-auth servers — it has no field for a custom X-API-Key header. To reach a header-authenticated endpoint like Tarno, bridge to it with the mcp-remote helper, which runs locally over stdio and injects the header on each request.

Prerequisite: Node.js 18 or newer on your PATH (Claude Desktop invokes npx). Check with node --version.

1. Open your Claude Desktop config file (create it if it does not exist):

OS Path
macOS ~/Library/Application Support/Claude/claude_desktop_config.json
Windows %APPDATA%\Claude\claude_desktop_config.json

You can also reach it from Settings → Developer → Edit Config.

2. Add Tarno to mcpServers. Keep your key in an env entry (not inline in args) — this is the safe pattern and avoids a known Claude Desktop/Windows bug where a space inside an args value is mis-escaped when it invokes 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>"
      }
    }
  }
}

Replace <API_KEY> with your operator-issued key. (Because an API key never contains spaces, the inline form "--header", "X-API-Key:<API_KEY>" also works — but the env pattern above keeps the key out of the args list and dodges the space bug.)

3. Restart Claude Desktop fully (quit and reopen). Tarno then appears as a connected tool source; you can ask Claude to search brands or fetch a brand's detail, and it will call search_brands / get_brand_detail for you.

Troubleshooting: if the server does not appear, confirm node --version works in a terminal, that the JSON is valid (no trailing commas), and that the key is a live, scoped key — an unauthorized/forbidden tool error means the key is missing, invalid, or lacks brands:read.

For a programmatic client (connect + callTool) using @modelcontextprotocol/sdk, see the code samples.

See also