HystoreWiki

5 min de lecturaVer en Markdown

Referencia del MCP

Todo lo que una app de IA (o tú, escribiendo una) necesita para hablar con Hystore: las direcciones, el inicio de sesión OAuth paso a paso, el formato de los mensajes y cada herramienta con ejemplo. Para solo conectar una app lista, mira Conectar la IA.

Direcciones

Qué Dirección
Servidor MCP POST https://mcp.hystore.com.br/mcp
Metadatos del recurso (RFC 9728) GET https://mcp.hystore.com.br/.well-known/oauth-protected-resource/mcp
Metadatos del inicio de sesión (RFC 8414) GET https://mcp.hystore.com.br/.well-known/oauth-authorization-server
Registro de la app (RFC 7591) POST https://mcp.hystore.com.br/v1/oauth/register
Pantalla de autorización https://app.hystore.com.br/oauth/authorize
Token POST https://mcp.hystore.com.br/v1/oauth/token
Cerrar sesión (revocar) POST https://mcp.hystore.com.br/v1/oauth/revoke

Todas las rutas también están en la OpenAPI.

  • Transporte: Streamable HTTP sin sesión. Cada POST /mcp lleva un mensaje JSON-RPC y recibe una respuesta JSON. GET y DELETE responden 405.
  • Protocolo: 2025-11-25 (también 2025-06-18 y 2025-03-26).
  • Las páginas web (pedidos con encabezado Origin) no llaman a /mcp ni al token: llama desde un programa, no desde el navegador.

Cómo funciona el inicio de sesión

Es OAuth 2.1 con PKCE, como pide la especificación del MCP. Las apps listas hacen todo solas; los pasos de abajo muestran lo que pasa, con comandos que puedes ejecutar en la terminal.

1. Descubrir dónde iniciar sesión

Sin token, /mcp responde 401 y apunta a los metadatos:

Terminal
curl -i -X POST https://mcp.hystore.com.br/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize"}'
HTTP
HTTP/2 401
www-authenticate: Bearer resource_metadata="https://mcp.hystore.com.br/.well-known/oauth-protected-resource/mcp", scope="theme:read theme:write theme:publish-request"

Los metadatos dicen quién hace el inicio de sesión (authorization_servers), y los del servidor de inicio de sesión traen las direcciones de autorización, token y registro:

Terminal
curl https://mcp.hystore.com.br/.well-known/oauth-authorization-server
JSON
{
  "issuer": "https://mcp.hystore.com.br",
  "authorization_endpoint": "https://app.hystore.com.br/oauth/authorize",
  "token_endpoint": "https://mcp.hystore.com.br/v1/oauth/token",
  "registration_endpoint": "https://mcp.hystore.com.br/v1/oauth/register",
  "revocation_endpoint": "https://mcp.hystore.com.br/v1/oauth/revoke",
  "code_challenge_methods_supported": ["S256"],
  "token_endpoint_auth_methods_supported": ["none"],
  "scopes_supported": ["theme:read", "theme:write", "theme:publish-request"]
}

2. Registrar la app

La app se registra una vez y recibe un client_id público (sin secreto):

Terminal
curl -X POST https://mcp.hystore.com.br/v1/oauth/register \
  -H "Content-Type: application/json" \
  -d '{"client_name":"Mi app","redirect_uris":["http://127.0.0.1:8765/callback"]}'
JSON
{
  "client_id": "hys_cl_...",
  "client_name": "Mi app",
  "redirect_uris": ["http://127.0.0.1:8765/callback"],
  "grant_types": ["authorization_code", "refresh_token"],
  "token_endpoint_auth_method": "none"
}
  • La dirección de vuelta tiene que ser https, http de loopback (127.0.0.1, localhost, [::1]) o el esquema propio de una app (miapp:/callback).
  • El nombre aparece en la pantalla de autorización marcado como informado por la app.
  • Una app registrada y nunca usada se borra en 30 días.

3. Generar el PKCE

Terminal
VERIFIER=$(openssl rand -base64 48 | tr -d '=+/' | cut -c1-64)
CHALLENGE=$(printf %s "$VERIFIER" | openssl dgst -sha256 -binary | openssl base64 | tr '+/' '-_' | tr -d '=')

4. Mandar a la persona a autorizar

Abre en el navegador (una sola línea):

https://app.hystore.com.br/oauth/authorize?response_type=code&client_id=hys_cl_...&redirect_uri=http%3A%2F%2F127.0.0.1%3A8765%2Fcallback&code_challenge=<CHALLENGE>&code_challenge_method=S256&scope=theme%3Aread%20theme%3Awrite%20theme%3Apublish-request&resource=https%3A%2F%2Fmcp.hystore.com.br%2Fmcp&state=<un valor aleatorio>

La persona entra al panel, elige la tienda y autoriza. El navegador vuelve a tu dirección con ?code=hys_ac_...&state=.... Revisa el state.

5. Cambiar el código por el token

Terminal
curl -X POST https://mcp.hystore.com.br/v1/oauth/token \
  -d grant_type=authorization_code \
  -d code=hys_ac_... \
  -d client_id=hys_cl_... \
  -d redirect_uri=http://127.0.0.1:8765/callback \
  -d code_verifier="$VERIFIER" \
  -d resource=https://mcp.hystore.com.br/mcp
JSON
{
  "access_token": "hys_at_...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "hys_rt_...",
  "scope": "theme:read theme:write theme:publish-request"
}

El token de acceso vale una hora y solo abre /mcp.

6. Renovar y cerrar sesión

Terminal
curl -X POST https://mcp.hystore.com.br/v1/oauth/token \
  -d grant_type=refresh_token \
  -d refresh_token=hys_rt_...

Cada renovación devuelve un par nuevo e invalida el anterior. Usar de nuevo un refresh_token ya cambiado revoca la sesión entera (alguien copió el token). La sesión dura 30 días desde el último uso.

Terminal
curl -X POST https://mcp.hystore.com.br/v1/oauth/revoke -d token=hys_rt_...

Mensajes

Cada llamada es un POST /mcp con el token y un mensaje JSON-RPC:

Terminal
curl -X POST https://mcp.hystore.com.br/mcp \
  -H "Authorization: Bearer hys_at_..." \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "MCP-Protocol-Version: 2025-11-25" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

initialize

JSON
{ "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "protocolVersion": "2025-11-25", "capabilities": {}, "clientInfo": { "name": "mi-app", "version": "1.0.0" } } }

La respuesta trae serverInfo (hystore), la capacidad tools e instructions: un texto corto que le explica a la IA cómo trabajar con el tema (leer la guía primero, editar el borrador, mostrar la vista previa, pedir publicación).

tools/call

JSON
{
  "jsonrpc": "2.0",
  "id": 7,
  "method": "tools/call",
  "params": { "name": "read_theme_file", "arguments": { "path": "sections/hero.liquid" } }
}
JSON
{
  "jsonrpc": "2.0",
  "id": 7,
  "result": {
    "content": [{ "type": "text", "text": "path: sections/hero.liquid\nsha256: 3f1c...\n\n<section class=\"hero\">..." }],
    "structuredContent": { "path": "sections/hero.liquid", "content": "<section class=\"hero\">...", "sha256": "3f1c..." }
  }
}

Una herramienta que rechaza algo responde con "isError": true y el motivo en el texto (y en structuredContent, cuando hay detalles). Los errores de protocolo (método desconocido, herramienta que no existe) vuelven como error de JSON-RPC.

Herramientas

Los nombres de los argumentos están en snake_case. El alcance es el permiso que la conexión necesita.

read_theme_guide

Lee la guía del tema (en inglés). Sin argumentos trae la guía entera; con section (parte del título de una sección, como Sections, Data o Apps), solo esa parte. Alcance: theme:read.

JSON
{ "name": "read_theme_guide", "arguments": { "section": "Sections" } }

get_store

Nombre y dirección de la tienda y los permisos de esta conexión. Sin argumentos. Alcance: theme:read.

list_theme_files

Los archivos del borrador con sha256, tamaño y la revision del borrador. Sin argumentos. Alcance: theme:read.

read_theme_file

Un archivo del borrador con su sha256, que devuelves como base_sha al escribir. Alcance: theme:read.

JSON
{ "name": "read_theme_file", "arguments": { "path": "layout/theme.liquid" } }

write_theme_files

Crea, cambia o borra (content: null) hasta 100 archivos de una vez: todos o ninguno. Alcance: theme:write.

JSON
{
  "name": "write_theme_files",
  "arguments": {
    "changes": [
      { "path": "sections/black-friday.liquid", "content": "<section class=\"bf\">...</section>\n{% schema %}{\"name\":\"Black Friday\",\"settings\":[]}{% endschema %}", "base_sha": null },
      { "path": "templates/home.json", "content": "{\"sections\":{\"bf\":{\"type\":\"black-friday\"}},\"order\":[\"bf\"]}", "base_sha": "9a0b..." },
      { "path": "sections/old-banner.liquid", "content": null }
    ],
    "expected_revision": 12
  }
}
  • base_sha: el sha256 que leíste. Si el archivo cambió desde entonces, no se escribe nada y la respuesta trae conflict. null quiere decir "el archivo todavía no puede existir".
  • expected_revision (opcional): la revision del borrador que leíste; si otra escritura pasó antes, no se escribe nada.
  • Un archivo con error vuelve en problems, con path, line, code y message. No se escribe nada.

Éxito:

JSON
{ "revision": 13, "files": [{ "path": "sections/black-friday.liquid", "sha256": "..." }], "warnings": [] }

Rechazo:

JSON
{ "refused": true, "problems": [{ "path": "sections/black-friday.liquid", "line": 3, "code": "html_event_handler", "message": "Event attributes (onclick, onload...) are not allowed. Use data-hystore-* components.", "severity": "error" }] }

check_theme

Revisa el borrador entero (la misma revisión de antes de publicar): errores y avisos con archivo y línea. Sin argumentos. Alcance: theme:read.

Un enlace de 24 horas que abre el borrador en la dirección real de la tienda y se recarga solo con cada cambio. Entrégalo a la persona para que mire. Sin argumentos. Alcance: theme:read.

request_publish

Pide la publicación del borrador actual; alguien con permiso aprueba en Personalización > Tema en código. Alcance: theme:publish-request.

JSON
{ "name": "request_publish", "arguments": { "note": "Banner de Black Friday arriba en el inicio" } }

list_versions, read_version_file, restore_version

Las últimas 30 versiones publicadas; un archivo como estaba en una versión (content: null cuando ella no tenía el archivo); y volver una versión al borrador (la tienda en el aire no cambia hasta que se apruebe una publicación). Alcances: theme:read para leer, theme:write para restaurar.

JSON
{ "name": "read_version_file", "arguments": { "version": 3, "path": "styles/theme.css" } }
JSON
{ "name": "restore_version", "arguments": { "version": 3 } }

list_assets, upload_asset, delete_asset

Imágenes y fuentes del borrador, con su dirección pública. Úsalas en el tema como {{ 'nombre.webp' | asset_url }} o url(assets/nombre.webp). Alcances: theme:read para listar, theme:write para enviar y borrar.

JSON
{ "name": "upload_asset", "arguments": { "path": "assets/banner.webp", "base64": "UklGRl..." } }

PNG, JPEG, WebP, GIF y AVIF hasta 3 MB; WOFF y WOFF2 hasta 1 MB. El tipo se lee del contenido, no del nombre. SVG no entra como archivo de medios.

read_catalog

Lo que un visitante ve de la tienda: categorías y productos activos (id, nombre, slug, precio en centavos, imagen). Usa los ids en data-hystore-add-to-cart y los slugs en {% load products, category: '...' %}. Sin argumentos. Alcance: theme:read.

Límites

  • 120 lecturas y 30 escrituras por minuto por conexión; arriba de eso, 429 con Retry-After (en segundos).
  • Archivos: 256 KB cada uno, 400 archivos, 5 MB de texto. Medios: 100 archivos, 40 MB.
  • Una escritura lleva hasta 100 cambios.

Seguridad

  • El token de la app solo abre /mcp. Las llaves y las sesiones de la herramienta hystore no abren /mcp, y el token de la app no abre la API del tema.
  • Ninguna herramienta toca pedidos, pagos, jugadores, cupones ni configuración, y ninguna publica sola.
  • El texto que viene de la tienda (nombres de producto, descripciones) se trata como dato, nunca como instrucción para la IA.