Qué necesita un agente que una API REST no le da
En este sitio hay una API REST, y a un programador que la integre le irá bien. A un agente no: no puede abrir la referencia, decidir cuál de tres endpoints quiere, y montar a mano una petición con la cadena de consulta correcta. Le pregunta a un servidor qué puede hacer, recibe esquemas legibles por máquina, y llama a una.
Así que todo lo que hace el servicio se expone una segunda vez, como herramientas. Seis de ellas, y ningún estado que gestionar entre llamadas:
| Herramienta | Para qué sirve |
|---|---|
create_inbox | Inventa una dirección nueva que el agente puede dar de inmediato. No se reserva nada en el servidor, así que no puede fallar. Admite un prefix legible opcional; un sufijo aleatorio la mantiene única. |
list_domains | Los dominios públicos que cualquiera puede usar — útil cuando un formulario acaba de rechazar uno de ellos. |
list_messages | Todo lo que espera en una dirección, lo más reciente primero. Responde al instante, incluso cuando no hay nada. |
read_message | Un mensaje completo: remitente, asunto, texto plano, HTML, adjuntos. Aquí es donde está el código o el enlace de acceso. |
wait_for_message | Espera hasta que llega algo, y luego lo devuelve completo. La herramienta que hay que llamar en el momento en que se envía un formulario. |
delete_message | Elimina uno ahora en lugar de esperar 5 días a que caduque. Es idempotente, así que a un agente reintentarlo no le cuesta nada. |
El servidor también responde a initialize con un breve párrafo de instrucciones, que la mayoría de los clientes pasan directamente al modelo. Así, un agente llega ya sabiendo para qué sirve este servicio y cuál es su única advertencia real, sin que nadie tenga que escribirlo en un prompt.
Conectar un cliente en una línea
El endpoint es una sola URL, y no hay nada a lo que registrarse en los dominios públicos. Todos los clientes MCP usan el mismo tipo de configuración — Claude Desktop, Claude Code, Cursor, Continue, el OpenAI Agents SDK y cualquier otro que hable el protocolo:
{"mcpServers":{"grabmail":{"url":"https://grabmail.io/mcp"}}}El transporte es Streamable HTTP: un POST que lleva JSON-RPC 2.0, una respuesta JSON, ningún flujo que se quede abierto. Así que puedes comprobar todo esto desde una terminal antes de que intervenga ningún agente:
curl -sX POST https://grabmail.io/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'Los clientes que buscan un servidor antes de preguntarle a un humano encontrarán /.well-known/mcp.json en el dominio, que indica ese mismo endpoint y su transporte.
Todo el flujo de registro, en cuatro llamadas a herramientas
Esta es la secuencia que necesita casi cualquier agente, y no hay nada más que añadir:
- Llama a
create_inbox. Devuelve una dirección, un alias, el dominio, y una nota que le dice al agente cuál de los dos entregar. No se creó nada — el buzón empieza a existir cuando llega a él el primer mensaje. - Pon el alias en el formulario. El servicio al que te registras recibe una dirección funcional que llega al buzón y no puede usarse para leerlo.
- Llama a
wait_for_messagecon la dirección. Justo después de enviar el formulario, no con un temporizador. Espera; no consulta en un bucle que el agente tenga que escribir. - Lee el código dentro del mensaje. El cuerpo completo llega junto con la espera, así que normalmente no hace falta una segunda llamada —
read_messagesolo hace falta para algo que llegó antes.
Por qué wait_for_message responde antes de que llegue el correo
Es la herramienta que hace que un agente funcione de verdad, y la que más sorprende por su comportamiento, así que merece un minuto. Una llamada tiene este aspecto:
curl -sX POST https://grabmail.io/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":
{"name":"wait_for_message",
"arguments":{"address":"demo.5kuqarzuch@grabmail.io",
"subject_contains":"code"}}}'Espera hasta 25 segundos. Si para entonces no ha llegado nada, no falla — vuelve con una respuesta clara y pide que se la llame de nuevo:
{
"timed_out": true,
"waited_seconds": 25,
"message": null,
"note": "Nothing arrived yet. Call wait_for_message again ..."
}- Por qué tiene un límite
- Cada segundo de espera es un worker del servidor que no hace más que dormir, y hay un número fijo de ellos. Una espera que pudiera durar cinco minutos sería un agente ocupando un puesto que necesitan otros cien. 25 segundos también cabe dentro del tiempo de espera por defecto de cualquier cliente, así que la llamada responde en vez de que el cliente se rinda antes.
- Solo 8 esperas a la vez
- Pasado ese número, la herramienta responde de inmediato con
timed_outy una nota que lo explica. Que te digan que vuelvas es mejor que quedar en cola detrás de otros siete agentes sin ninguna forma de saberlo. - Filtrado, para que el correo equivocado no la interrumpa
from_containsysubject_containshacen que la espera ignore cualquier otra cosa que llegue mientras tanto.since_ides el que hay que pasar cuando el buzón ya tenía algo dentro: dale el id más reciente ya visto y solo un correo genuinamente nuevo satisfará la llamada.
Da el alias, consulta la dirección
Cada buzón aquí tiene una segunda dirección, de doce caracteres, que entrega en el mismo buzón pero no puede leerlo. Esa distinción importa mucho más para un agente que para una persona, porque un agente pegará sin dudar lo que sea que se le dio en cualquier campo que encuentre.
Así que create_inbox no simplemente devuelve una dirección y confía en que salga bien. Devuelve las dos, y un next_step que dice cuál es cuál — el agente lee el resultado de su propia herramienta, así que la instrucción llega justo donde se necesita en lugar de quedarse en una página de documentación que nadie en el bucle puede leer.
Qué poner en las instrucciones del propio agente
Las herramientas se describen a sí mismas lo bastante bien como para que un modelo capaz lo haga bien sin que se le indique. Cinco líneas lo hacen fiable en vez de solo probable:
- Una dirección por registro. No una dirección reutilizada en todas partes: un buzón con el correo de seis servicios son seis confirmaciones que el agente tiene que distinguir, y una sola fuga que las expone todas.
- Da el alias, nunca la dirección. Merece la pena decirlo explícitamente, aunque el resultado de la herramienta ya lo diga.
- Llama a
wait_for_messagejusto después de enviar el formulario, y vuelve a llamarla si respondetimed_outen lugar de tratarlo como un fallo. Dos o tres veces es normal. - Pasa
since_idcuando el buzón no es nuevo, o un mensaje antiguo satisfará la espera y el agente leerá un código que caducó hace una hora. - Elimina el mensaje en cuanto se use el código. No es obligatorio — todo desaparece en 5 días de todas formas — pero cierra la ventana antes y cuesta una sola llamada idempotente.
Escrito como bloque de instrucciones, viene a ser tan largo como esto:
Cuando necesites una dirección de correo, llama a create_inbox y da el ALIAS
que devuelve, nunca la dirección. Justo después de enviar el formulario, llama a
wait_for_message con la dirección. Si responde timed_out, vuelve a llamarla —
eso es normal y no se ha perdido nada. Pasa since_id si el buzón ya tenía correo.
Elimina el mensaje en cuanto se haya usado el código.Los límites que conviene conocer antes de construir sobre esto
Todos están publicados en lugar de tener que descubrirlos, y ninguno tiene un plan que los amplíe:
| Límite | Valor | Qué significa para un agente |
|---|---|---|
| Una espera | 25 segundos | Luego timed_out. Vuelve a llamar; no lo trates como un error. |
| Esperas simultáneas | 8 | Pasado ese número, la herramienta responde al instante y lo indica. Recurre a list_messages. |
| Lecturas | Una por segundo, por dirección | Muy por encima de lo que hace un bucle de llamadas a herramientas. Una espera bloqueante es una sola solicitud, no sesenta. |
| Tamaño del mensaje | 5 MB | Se rechaza durante la conversación SMTP, así que se avisa al remitente en lugar de dejar al agente esperando algo que nunca va a llegar. |
| Retención | 5 días | Un límite estricto que aplica un proceso automático. Cualquier cosa que el agente deba conservar, tiene que anotarla por su cuenta. |
No hay ningún endpoint de envío ni ninguna herramienta para eso. Este servicio solo recibe, que es lo que evita que un buzón sin autenticación se convierta en un relay de spam — así que un agente que necesite responderle a un humano necesita un buzón real en otro lugar.
Cuando un formulario rechaza los dominios públicos
Muchos servicios mantienen listas de dominios de correo desechable, y los tres dominios públicos de aquí están en ellas. Un agente se encuentra esto como un formulario que rechaza la dirección que se le acaba de dar, o peor, la acepta y nunca envía nada.
La solución duradera es un dominio propio. Un registro MX convierte cada dirección de ese dominio en un buzón aquí, no está en ninguna lista porque no aparece impreso en ninguna parte de este sitio, y las mismas seis herramientas funcionan en él sin cambios — create_inbox es la única que no, ya que esa inventa direcciones en los dominios públicos. El agente simplemente usa you-pick-it@your-domain y llama a wait_for_message sobre esa dirección.
Registro MX para tu dominio10 smtp.grabmail.io
Aquí está la guía completa paso a paso: el registro, qué demuestra publicarlo, y los límites de un buzón sin contraseña.
Qué no dejar que un agente haga con esto
La parte honesta, y la que te ahorra una tarde:
- Nada que necesites poder recuperar. Nada que contenga dinero, identidad o trabajo. El buzón vuelve a estar vacío en 5 días y puede leerlo quien conozca la dirección, así que un restablecimiento de contraseña enviado ahí el año que viene no llega a nadie — o le llega a otra persona.
- No como segundo factor. Un buzón sin contraseña no es un factor.
- No para nada privado. No porque lo leamos nosotros, sino porque la dirección es el único secreto en juego y es bastante posible que un agente la haya escrito en un log, una transcripción o un mensaje de commit.
- No para volumen. Un agente que abre cuentas por centenares es exactamente el comportamiento para el que existe cada lista de bloqueo, y es la forma más rápida de conseguir que los dominios públicos queden rechazados para todos los demás.
Usado para lo que es — el paso de confirmación que se interpone entre un agente y lo que de verdad se le pidió hacer — elimina el único paso que lo detiene de forma fiable.
Preguntas
¿Necesito una clave de API o una cuenta?
No. Los dominios públicos, las herramientas y un dominio propio son todos gratuitos y sin autenticación. El único caso que lleva clave es un dominio que se ha cerrado a petición, que entonces exige una cabecera Authorization.
¿Con qué clientes funciona esto?
Cualquier cliente que hable el Model Context Protocol — Claude Desktop, Claude Code, Cursor, Continue, el OpenAI Agents SDK y los demás. El transporte es Streamable HTTP, que es lo que usan por defecto los clientes actuales, y se aceptan tres versiones del protocolo para que uno más antiguo también pueda conectarse.
¿Por qué wait_for_message devuelve timed_out?
Porque una sola espera tiene un tope de 25 segundos, a propósito. No es un error y no se ha perdido nada: vuelve a llamarla. El correo tarda a menudo más de lo que sugiere la página que lo prometió, y dos o tres esperas seguidas son un registro normal.
¿Puede el agente usar mi propio dominio en su lugar?
Sí, y no cambia nada salvo la dirección. Apunta un registro MX a smtp.grabmail.io y cada dirección de ese dominio se vuelve legible a través de las mismas herramientas. Solo create_inbox funciona exclusivamente en los dominios públicos, porque es la que inventa un nombre por ti.
¿Puede un agente enviar correo con esto?
No. No hay ninguna herramienta de envío ni ningún endpoint de envío, por diseño: un servicio sin autenticación que pudiera enviar correo sería un relay de spam en menos de un día. Nuestro SPF es v=spf1 -all y nuestro DMARC es p=reject, así que cualquier cosa que diga venir de una dirección de aquí está falsificada.
¿Es privado el buzón?
No, y esta es la única advertencia que hay que darle a un agente de forma explícita. En un dominio público, cualquiera que conozca o adivine la dirección puede leerlo. Usa una dirección difícil de adivinar, da el alias en lugar de la dirección, y no dejes que nada privado se le acerque.
¿Pueden dos agentes esperar a la vez en la misma dirección?
Sí, y a los dos se les entregará el mensaje cuando llegue. Lo que tiene un tope es el número de esperas que ocurren a la vez en todo el servicio, 8; pasado ese número, la herramienta responde de inmediato y lo indica, y list_messages sigue funcionando.
¿Cuánto duran los mensajes?
5 días desde que llegan, leídos o no, y no hay ningún ajuste que lo extienda. Cada mensaje lleva expires_at, así que un agente nunca tiene que calcular esa fecha por su cuenta.
¿En qué se diferencia esto de llamar a la API REST desde un script?
Para un script no es diferente, y la API REST es la opción más adecuada — la guía para probar flujos de verificación cubre esa forma de trabajar, plazos y ayudantes incluidos. MCP es para el caso en que nadie ha escrito el bucle: el modelo decide abrir un buzón, y necesita que las herramientas se puedan descubrir, no que estén documentadas.


