Skip to main content
Glama

Shopify MCP Demo

Compra en una tienda Shopify en vivo desde ChatGPT o Claude y paga con Cashfree — catálogo, carrito, inicio de sesión con OTP, direcciones guardadas y pago, sin salir de la conversación.

"show me shirts from the store"
      ↓  SearchProducts
  product grid  ⇄  product detail
        └────────┬───────┘
                 ↓
  cart  →  phone  →  OTP  →  address  →  payment
                                            ↓
                            Cashfree  →  order summary

Cada ruta de pago termina en la misma pantalla: lo que se compró, con cantidades y precios, más el ID del pedido y el estado. Cashfree confirma que el dinero se movió, pero nunca vio el carrito de Shopify, por lo que no puede decir qué contenía.

Vuelve a buscar después de pagar y el widget inicia una nueva sesión de compra — carrito nuevo, sin recibo residual. Comprar dos veces en una misma conversación funciona.

Cómo funciona

El servidor es tres cosas a la vez:

  • un servidor MCP para el anfitrión de IA, exponiendo una herramienta orientada al modelo (SearchProducts) más un recurso de widget.

  • un cliente MCP para Shopify, que habla JSON-RPC con https://{SHOP_DOMAIN}/api/ucp/mcpsin autenticación, el dominio de la tienda es toda la configuración.

  • un cliente REST para Cashfree, para la creación de pedidos, inicio de sesión con OTP, direcciones guardadas y estado del pedido.

El widget React posee todo el recorrido. Solo la búsqueda de productos llega al modelo; todo lo posterior es widget-a-servidor, lo que mantiene el flujo determinista.

La navegación consta de dos pantallas. La cuadrícula muestra una tarjeta por producto con su rango de precios y cuántas opciones tiene; al tocar una se abre una pantalla de detalle con la descripción, el selector de variantes y Añadir al carrito. Un producto con una sola variante se puede añadir directamente desde su tarjeta, y un producto que ya está en el carrito obtiene un selector de cantidad allí — así que los casos comunes cuestan un toque y solo una elección real cuesta una pantalla. Ambas pantallas muestran una insignia con lo que ya está en el carrito, y los dos recuentos provienen de la misma función.

Related MCP server: Shopify Agentic MCP Gateway

Configuración

npm install
cp .env.example .env      # set SHOP_DOMAIN and the Cashfree keys
npm run build
npm start

Exponlo (ngrok http 8787), configura SERVER_URL en .env con el origen público, reinicia, luego añade <public-origin>/mcp como conector en tu anfitrión.

Basta con un reinicio — no hace falta recompilar. El origen se lee al arrancar y se inyecta en el HTML del widget cada vez que se sirve el recurso.

Variable

Propósito

SHOP_DOMAIN

La tienda. Cambia de tienda editando esta línea y reiniciando.

UCP_AGENT_PROFILE

Obligatorio en cada llamada UCP. El perfil de ejemplo público de Shopify es suficiente para una demo.

CASHFREE_ENV

sandbox (por defecto) o production.

CASHFREE_CLIENT_ID / CASHFREE_CLIENT_SECRET

Panel → Desarrolladores → Claves API.

CASHFREE_RETURN_URL

Lugar al que Cashfree devuelve al comprador. Por defecto, una página alojada estable.

SERVER_URL

Origen público cuando se usa un túnel.

PORT

Por defecto 8787.

PAYMENT_ANNOTATIONS

honest (por defecto) o readonly. Cámbialo en .env y reinicia para probar ambas rutas de envío. readonly hace que las herramientas de pago afirmen ser de solo lectura para que el anfitrión las envíe — solo diagnóstico, ver más arriba. Una variable de shell anula el archivo, porque --env-file no sobrescribe una variable de entorno ya definida.

Qué esperar al ejecutarlo

El pago funciona, excepto las tarjetas guardadas. El anfitrión filtra las herramientas de pago según sus anotaciones MCP. cashfree-here envía las honestas — { readOnlyHint: false, destructiveHint: true } para una herramienta que cobra en una tarjeta — y frente a esas el anfitrión se niega a enviarlas: el modelo forma la intención, el anfitrión precarga la plantilla del widget de la herramienta, y nunca llega un tools/call.

Configurar PAYMENT_ANNOTATIONS=readonly las anula a { readOnlyHint: true, destructiveHint: false } y cuatro de las cinco herramientas se envían: UPI, banca por internet, pago alojado, tarjeta nueva — y, una vez que la transferencia aterriza, también tarjeta guardada.

Esa bandera es una medición, no una solución. Hace que una herramienta que mueve dinero afirme que no hace nada, lo cual es una mentira al control exacto que existe para detectarlo. Está desactivada por defecto, imprime una advertencia en el primer uso y no debe distribuirse.

Cuando una herramienta está bloqueada, el widget lo indica y ofrece un enlace de Cashfree, que funciona. Paga en la pestaña, vuelve, y el widget confirma el pedido.

La transferencia llega tarde, no se pierde — y "bloqueado" puede ser incorrecto. Este archivo solía decir que la transferencia widget-a-modelo fallaba aproximadamente la mitad de las veces. Una sesión capturada dice lo contrario: CheckoutTool fue declarado bloqueado tras los dos intentos del widget (2 × 4s), el comprador tomó el enlace de Cashfree, y el tools/call llegó de todas formas — aproximadamente 2-4s después del clic, así que alrededor de 12-20s de principio a fin. El servidor lo manejó en 37ms. Cada milisegundo de ese retraso fue aguas arriba.

sendFollowUpMessage no le pide al anfitrión que ejecute una herramienta. Publica un turno de usuario y se resuelve una vez que ese mensaje se entrega, así que la ventana de confirmación del widget comienza en el momento de la cola y luego mide un turno completo de inferencia del modelo en la infraestructura del anfitrión — contra el cual el tiempo de espera de 4s nunca fue calibrado.

La consecuencia es peor que una pantalla lenta: el comprador pagó en el enlace externo mientras un widget de Cashfree para el mismo payment_session_id se mostraba detrás de él. Dos superficies de pago activas para un pedido. DISPATCH_ATTEMPTS = 2 envía el seguimiento dos veces, por lo que también son posibles dos widgets.

La lectura de "falla la mitad de las veces" fue un error nuestro. Se estaban abriendo dos instancias de App en el único canal postMessage que proporciona el transporte de MCP Apps: useMcpApp construyó y conectó una para renderizar, getClientPlatform() construyó y conectó otra para la transferencia de pago. Las negociaciones compitieron, y la que perdió respondió "Not connected" a todo lo posterior — un comprador seleccionó un método de pago y nunca llegó un tools/call al servidor. Una transferencia de cara o cruz es lo que parece una compencia de dos vías, no un anfitrión inestable. El hook ahora se suscribe al cliente compartido, connect() es idempotente, y desmontar ya no llama a close() en un singleton que sobrevive al árbol de React.

Desde esa corrección, cada envío ha aterrizado al primer intento. attemptsFor() ya devuelve 1 en anfitriones MCP Apps, por lo que el reintento solo se aplica a ChatGPT, que usa LegacyOpenAiClient y nunca tuvo esta competencia — no hay medición que justifique su eliminación, así que se mantiene.

UPI falla por encima de ₹1,00,000 con "el método de pago no es elegible para este pedido" — el límite por transacción de UPI, confirmado por bisección en ₹99,600 (ok) / ₹1,00,800 (fallo). La banca por internet y el pago alojado tienen límites más altos. El carrito no tiene techo, así que unos pocos toques en + pueden superarlo sin advertencia.

Recargar la ventana del anfitrión es seguro, en ambos anfitriones. El carrito, el paso de pago, las direcciones guardadas y la pantalla de pago vuelven; el cuerpo del carrito se restaura desde el estado persisitido en lugar de volver a buscar, por lo que una recarga no cuesta llamadas a Shopify en absoluto en Claude. ChatGPT no vuelve a entregar el resultdo de la herramienta, por lo que cuesta una search_catalog para reconsruir la cuadrícula de productos y nada más. Medido en cuatro flujos con recargas en varios pasos: 18 llamadas aguas arriba, ninguuna repetida.

El ID de compilación se imprime en la pantalla de pago. Los anfitriones almacenan en caché las instancias del widget, y una en caché es indistinguible de una actual — varias rondas de depuración se fueron en código que ya había sido eliminado. Si el ID de compilación no coincide con el servidor en ejecución, estás viendo un widget obsoleto.

Una recompilación no llega al navegador, ni tampoco una nueva conversación. La URI del widget lleva el ID de compilación, así que cada compilación es un recurso distinto, y eso todavía no es sufiiente: Clude sirvió un widget en caché a través de recompilaciones y conversaciones nuevas, sin ningún resources/read en el regisro en absoluto. Dos rondas de depuración se fueron en instrumentación que nunca se ejecutaba. La única forma confiable de forzar una relecura es desconectar y reconectar el conector. Verifica si hay POST /mcp (resources/read ui://widget/shopify-store-<build>.html) en el regisro antes de confiar en cualquier cosa que veas.

Reconectar todavía no es toda la hstoria: los metadatos de la herramienta en caché del anfitrión pueden nombrar una URI de una compilación anterior, así que incluso una conversación nueva puede pedir un ID de compilación que este servidor ya no tiene. Responde por cualquiera de ellos — ver "Versionar la URI del widget la retira" más abajo — pero el ID en esa línea de resources/read es el del anfitrión, no necesariamente el del servidor en ejecución. window.__BUILD__ en la pantalla de pago es lo que dice qué paquete se está ejecutando.

Limitaciones conocidas

  • La entrada de tarjeta no se puede renderizar en Claude y no se corregirá upstream. Cashfree Elements monta sus campos PCI como iframes anidados de origen cruzado. Claude aplica frame-src 'self' blob: data: e ignora los frameDomains que declara un recurso de UI, por lo que los campos se cargan vacíos, como cuadros no cliqueables. Esto es política, no un error en tránsito: un ingeniero de Anthropic declaró el 2026-04-09 en claude-ai-mcp#40 que los iframes anidados no están permitidos por razones de seguridad, y dos preguntas posteriores de "¿permanente o temporal?" quedaron sin respuesta. connectDomains y resourceDomains se corrigieron en abril y funcionan — solo el framing está bloqueado, por lo que fetch desde el widget a este servidor funciona bien.

    Stripe se encontró con el mismo muro: su documentación de MCP Apps abre una página de Checkout alojada con app.openLink() en lugar de incrustar campos de tarjeta. Eso tiene la misma forma que CheckoutTool aquí, que funciona hoy y es la ruta recomendada para tarjetas en Claude.

    Mantener la entrada de tarjeta en la conversación es posible — campos <input> simples (sin iframe) que publican directamente a este servidor, que es lo que cashfree-here enviaba antes del commit 55da139 que lo reemplazó con Elements. Pone PANs en bruto a través de nuestro servidor (territorio SAQ-D) y 3DS aún redirige fuera, por lo que compra la forma pero no el flujo. No construido; una decisión de producto, no técnica.

  • El pago con tarjeta guardada falla dentro de Cashfree. CardPaymentTool envía y lista tarjetas guardadas correctamente, pero pagar con una devuelve HTTP 500 {"message":"Internal Server Error"} desde /pg/orders/sessions/js. Aislado en un pedido: UPI y banca por internet ambos devuelven 200 contra el mismo payment_session_id y cabeceras; solo la rama payment_method.card.instrument_id da 500, con o sin CVV. Un 500 genérico es un fallo del lado de Cashfree — sus errores de validación son 400 con mensajes específicos. Necesita a Cashfree.

  • UPI se ofrece por encima de su límite de ₹1,00,000 y falla en Cashfree en lugar de estar deshabilitado en el selector.

  • cashfree-here está parcheado en el lugar. Dos correcciones viven en el checkout hermano, no en este repositorio: useReconciliation.start() ahora limpia el temporizador de sondeo anterior, y la notificación de pago exitoso se dispara una vez por pedido. Sin ellas, un pedido pagado publicaba "Payment completed successfully" en el chat cada pocos segundos, para siempre.

  • La dirección seleccionada no está vinculada al pedido. El comprador elige una y no se le informa a Cashfree. Sin resolver; necesita una respuesta del equipo de OCC.

  • No se crea ningún pedido en Shopify. El pedido vive solo en Cashfree. Crear uno necesita credenciales de la API de Administración de Shopify, que este proyecto evita deliberadamente.

  • El almacén de sesiones está en memoria. Un reinicio del servidor pierde un checkout en curso.

  • Las ofertas y cupones están diferidos. Ambas APIs están probadas y documentadas en docs/cashfree-occ-api.md; solo falta la UI.

  • Solo INR, coincidiendo con las tiendas demo.

Notas para cualquiera que extienda esto

Hallazgos que costaron tiempo real establecer. Cada uno está medido, no asumido.

Shopify

  • Apunte solo a /api/ucp/mcp. La más antigua /api/mcp está obsoleta después del 2026-08-31 y lo dice en cada respuesta.

  • Los documentos publicados son incorrectos en tres lugares: invierten la división de endpoints de catálogo/carrito, y documentan las líneas del carrito como merchandise_id cuando UCP requiere line_items[].item.id. Los tipos aquí provienen de payloads capturados en src/lib/ucp/__fixtures__/, no de los documentos.

  • update_cart es declarativo — envíe el conjunto completo de líneas deseadas cada vez; la eliminación se expresa omitiendo una línea.

  • El dinero está en unidades menores con la moneda mantenida una vez a nivel de carrito. formatMoney toma el conteo decimal de Intl, por lo que las monedas de cero decimales no se dividen.

  • Una tienda protegida con contraseña aún sirve enlaces de catálogo, carrito y checkout. Solo navegar por la tienda llega a la página de contraseña.

  • search_catalog devuelve descripciones de productos como HTML, y las variantes llevan sus ejes como options: [{ name, label }]. La descripción se reduce a texto plano en normalise.ts antes de llegar a React: es contenido controlado por la tienda que se renderiza en la misma pantalla que recoge un OTP, y ningún formato en él vale una superficie de inyección.

  • Un producto de variante única aún tiene una opción — el marcador de posición { name: "Title", label: "Default Title" } de Shopify. Renderizarlo pone "1 titles" debajo de un producto que no tiene opciones que elegir.

Cashfree

  • x-chxs-id es el payment_session_id de Crear Pedido. Eso obliga a que el pedido exista antes del inicio de sesión. Uno fabricado devuelve payment_session_id_invalid.

  • Las llamadas OCC necesitan exactamente tres cabeceras. Ninguna de las huellas digitales del navegador en las solicitudes capturadas — ids de dispositivo, token de Forter, cookies, origen — se aplica.

  • Las direcciones requieren una línea de dirección combinada de 10–185 caracteres. Más corta es un 400 sin pista en la UI a menos que lo verifique.

  • La respuesta de creación de dirección es { shipping_address, billing_address }, no una lista. Analizarla como una devuelve un array vacío en caso de éxito.

  • /api/orders/:id hace proxy del cuerpo bruto de Cashfree, porque la reconciliación de cashfree-here analiza esa forma.

El widget

  • Una tarjeta es un producto; una línea de carrito es una variante, y no coinciden. Colapsar tres colores de una camiseta en una tarjeta es correcto para navegar y ambiguo para un stepper — un menos debajo de una tarjeta que tiene un Rojo y un Azul tiene que adivinar cuál quitar. La tarjeta cuenta cuántas variantes del producto están en el carrito y ofrece un stepper solo cuando la respuesta es exactamente una; de lo contrario, muestra la insignia del total y envía al comprador a la pantalla de detalle. Rechazar es más barato que eliminar algo que no eligieron.

  • La pantalla de detalle no tiene estado propio. El producto y la variante seleccionados viven en el estado del widget, porque el widget se vuelve a montar mientras el comprador se desplaza (ver más abajo) y un useState local perdería la selección con él. Se borran con un nuevo searchId, o el producto de la búsqueda anterior se reabriría sobre los nuevos resultados.

Este host

  • Verifica Access-Control-Allow-Headers antes de culpar a la plataforma. Este archivo solía afirmar que las solicitudes GET desde el iframe del widget nunca llegaban al servidor. Sí lo hacen. cashfree-here envía ngrok-skip-browser-warning en su GET de conciliación, lo que hace que la solicitud sea prefligada; nuestra lista de permitidos no incluía ese encabezado, por lo que el navegador rechazó la preflight y el GET nunca se envió. La conciliación entonces reportó "No se puede verificar el estado del pago" y mostró Pago fallido en pedidos que ya estaban PAGADOS.

    Dos cosas hicieron que pareciera un muro de plataforma: nunca apareció un GET en el registro, y las preflights se filtraron del registro como ruido — por lo que una solicitud rechazada y una solicitud nunca realizada eran indistinguibles. Ahora se registran las preflights en /api/*.

    Los endpoints solo POST (/api/pay/addresses/list, /api/orders/status) se construyeron sobre ese diagnóstico erróneo. Funcionan, pero no son necesarios.

  • Solo una llamada a herramienta invocada por el modelo hace que el anfitrión renderice el outputTemplate de esa herramienta. callTool ejecuta el manejador y no renderiza nada.

  • window.open está bloqueado en el iframe del widget, y la apertura externa del anfitrión navegó fuera y mató el conector MCP en medio del pago. Un simple <a target="_blank"> es lo único que funciona.

  • El transporte MCP no tiene estado (sessionIdGenerator: undefined). Emitir identificadores de sesión mientras se construye un servidor nuevo por solicitud hace que todo después de initialize falle con "Servidor no inicializado".

  • El estado del widget sobrevive al widget, por lo que cada resultado de herramienta debe tener fecha. El anfitrión mantiene el estado para toda la conversación y rehidrata cada nuevo widget a partir de él. Una búsqueda después de un pago, por lo tanto, se despertaba manteniendo screen: "checkout" y respondía "muéstrame camisas" con el recibo anterior — y el siguiente artículo añadido terminaba en un carrito que Shopify ya había completado. SearchProducts ahora sella un searchId por llamada y el widget se reinicia en uno que no ha mostrado.

  • Quien sea dueño del estado es lo que un reinicio debe limpiar. useCart y useCheckoutFlow se siembran a sí mismos al montarse y nunca releen lo que se les pasó, por lo que limpiar solo el estado del widget no hizo nada y escribieron sus valores obsoletos directamente un render después. La sesión está claveada en searchId para que React los descarte en su lugar.

  • Deriva un reinicio durante el render, no en un efecto. Un efecto pinta la pantalla antigua primero; un comprador que pedía pantalones veía aparecer el "Pago recibido" del pedido anterior y luego ser reemplazado.

  • Nada ordena las escrituras entre widgets activos. Cada widget anterior en una conversación sigue ejecutándose y escribe en una clave localStorage de todo el origen. Un contador de revision evita que una instantánea obsoleta reemplace una más reciente dentro de una instancia; no ordena las escrituras entre instancias, porque cada una incrementa su propio contador. Clavear el estado por conversación lo arreglaría correctamente.

  • Un widget se remonta mucho más a menudo de lo que parece, y la preflight CORS es cómo lo sabes. Claude destruye y recrea el iframe del widget a medida que el comprador se desplaza, y sirve el HTML desde su propia caché — por lo que no aparece ningún resources/read y el remonte es invisible en el registro. Lo que lo delata es OPTIONS /api/shop/cart: una preflight se almacena en caché por documento, por lo que una nueva significa un documento nuevo. Medido a las 22:48:29 y 22:52:25 mientras no ocurría nada más que desplazamiento. Cada pestillo, referencia y observador dentro del widget muere con él, por lo que "cargar esto una vez al montar" no es un límite de tasa — es una tasa por desplazamiento, por widget.

  • IntersectionObserver no te dice si el widget está en pantalla. La solución obvia anterior es obtener datos solo cuando es visible. No funciona: con un root nulo dentro de un contexto de navegación anidado, el observador mide contra el viewport de ese iframe, no el de la página anfitriona. Cada widget desplazado fuera de la vista se reporta a sí mismo como completamente visible. Construido, probado, medido, eliminado — tres widgets seguían obteniendo datos en cada recarga.

  • Almacena en caché lo que el anfitrión no devolverá. Con una rutina de remonte en lugar de rara, cualquier cosa que se vuelva a obtener al montar se vuelve a obtener constantemente: tres widgets activos significaban tres carritos recargados por recarga del anfitrión, y Shopify eventualmente respondió 429 Límite de tasa excedido. El cuerpo del carrito ahora se persiste con el id del carrito y una marca de tiempo, y solo se vuelve a obtener después de un TTL. Una sesión de tres flujos pasó de 19–20 llamadas upstream a 13, y dos recargas que solían costar seis llamadas ahora no cuestan ninguna.

    El TTL era de 30s al principio, lo que no prevenía nada: medido en tres flujos, la brecha entre la última obtención de un carrito y su siguiente montaje era de 32s, 41s, 41s, 42s, 53s, 80s y 143s — cada una de ellas expiraba la ventana. Ahora es de 10 minutos. El cuerpo es solo para mostrar; un cambio de cantidad se resiembra desde el servidor y el pago se cotiza desde el carrito de Shopify, por lo que no se puede pagar una cifra obsoleta.

  • Versionar la URI del widget la retira, por lo que sirve cada compilación. La URI lleva un id de compilación (ver más abajo) para vencer el almacenamiento en caché del anfitrión. El costo es que una recompilación invalida el id con el que se creó cada widget ya en una conversación: el anfitrión relee la URI que recuerda, el servidor responde -32602 Recurso no encontrado, y esos widgets renderizan "la tienda no pudo cargar". Un ResourceTemplate para ui://widget/shopify-store-{build}.html ahora sirve el paquete actual para ids retirados, lo que los actualiza en lugar de bloquearlos. Ten en cuenta que esto afecta también en una conversación nueva — los metadatos de herramienta en caché del anfitrión aún nombran la URI antigua.

  • Una advertencia CSP puede ser sobre algo que nunca elegiste enviar. MCPJam reportó https://cdn.openai.com bloqueado en cada herramienta. Las veinte referencias eran reglas @font-face en katex.min.css, extraídas por el barril ./css del SDK de Apps, para matemáticas que este widget no renderiza. Declarar el dominio habría hecho que un widget de Shopify y Cashfree dependiera del CDN de OpenAI dentro de Claude; importar las otras seis hojas por ruta en su lugar eliminó la referencia y 21KB de CSS. Ten en cuenta también que el modelo CSP de MCP Apps no tiene scriptSrc — solo connectDomains, resourceDomains y frameDomains — por lo que una queja de fuente de script no es algo que el servidor pueda responder.

  • Rechaza la rama GET de HTTP transmisible con 405, no 404. El transporte no tiene estado, por lo que no hay una transmisión de servidor a cliente que abrir. MCPJam abrió esa rama 97 veces en una sesión y tomó el 404 sin abortar, por lo que esto no es lo que lo rompe allí; se reporta que clientes más estrictos se rinden antes de initialize. 404 se lee como "no existe tal endpoint", que es una respuesta diferente e incorrecta.

  • Los costos de recarga difieren según el anfitrión, y es ChatGPT quien paga. En Claude una recarga ahora no cuesta nada: tanto el estado como el cuerpo del carrito vuelven del almacenamiento. En ChatGPT el catálogo no se reenvía, por lo que useProducts le pide a este servidor que lo haga — una search_catalog por recarga, y nada más.

Endpoints

Ruta

Propósito

POST /mcp

MCP sobre HTTP para el anfitrión de IA

POST /api/shop/cart

Crear/actualizar carrito contra Shopify

POST /api/shop/search

Recuperación de catálogo para un anfitrión que recargó sin reenviar el resultado de la herramienta

POST /api/pay/order

Crear el pedido de Cashfree, cotizado desde el carrito de Shopify

POST /api/pay/otp, /otp/verify

Inicio de sesión OTP

POST /api/pay/addresses/list, /addresses

Direcciones guardadas: leer y crear

POST /api/pay/dispatched

¿Se ejecutó realmente un manejador de herramienta de pago?

POST /api/orders/status

Estado del pedido para nuestra propia pantalla de verificación

GET /api/orders/:id

Cuerpo del pedido sin procesar para la conciliación de cashfree-here

Registros

Cada solicitud registra método, ruta, estado y duración; las llamadas MCP nombran el método y la herramienta, y las lecturas de recursos nombran la URI — POST /mcp solo es ilegible cuando cada llamada del anfitrión se ve idéntica.

13:59:48.201 → POST /mcp (tools/call SearchProducts) 200 328ms
13:59:52.884 → POST /api/shop/cart 200 904ms
14:00:03.117 → POST /api/pay/order 200 1026ms
14:00:09.640 ✗ POST /api/pay/addresses 502 121ms

La marca de tiempo está ahí porque las duraciones solas no pueden medir la brecha entre dos solicitudes, que es la única pregunta que importa cuando un envío de pago llega tarde.

Pruebas

npm test          # watch
npm run test:run
npm run type-check

Las pruebas se encuentran junto al código que cubren. Los fixtures en src/lib/ucp/__fixtures__/ son respuestas reales capturadas de Shopify, por lo que un cambio de forma falla una prueba en lugar de una demostración. Los fixtures de Cashfree están escritos a mano y redactados — sus tokens de sesión no deben ser confirmados.

Documentos

  • docs/cashfree-occ-api.md — el contrato OCC, verificado en vivo. No está en los documentos publicados de Cashfree.

  • docs/spikes/2026-08-12-occ-spike.md — lo que midió el spike.

  • docs/superpowers/specs/ — especificaciones de diseño para cada hito.

  • docs/superpowers/plans/ — los planes de implementación tarea por tarea en los que se convirtieron.

F
license - not found
Not graded
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

View all related MCP servers

Related MCP Connectors

  • Manage your Savanto store from your AI: catalog, content, prompts, and analytics, by chat.

  • Manage your NanoCart store from any AI agent: products, orders, coupons, subscribers, reports.

  • Amazon brand, seller, niche & buy-box intelligence inside your own Claude or ChatGPT.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/droiddevgeeks/shopify-mcp-demo'

If you have feedback or need assistance with the MCP directory API, please join our Discord server