Ghosty
Blog

El agente que no puede preguntar, adivina

Elicitation es el canal por el que un agente pide datos con un formulario de verdad en vez de escribirte un párrafo. Está en MCP y desde julio en ACP, Copilot ya lo tiene, y casi nadie lo emite todavía. Esto es qué resuelve y por qué importa más de lo que parece.

7 min de lecturaFixter
  • agentes
  • ACP
  • MCP
  • protocolos
  • elicitation
  • VS Code
Aguafuerte de Jacques Callot, c. 1621: una adivina rodeada de gente en un campamento, mientras a un lado le vacían los bolsillos a un incauto
The Stopping Place: The Fortune Teller, Jacques Callot, c. 1621–25 — Cleveland Museum of Art (CC0)

Hoy le pedimos a un agente nuestro —corriendo en una caja, conectado a VS Code— que levantara una página y nos diera un enlace público. No tenía forma de entregar nada: la sesión venía sin herramientas de entrega, y nadie se lo dijo.

Así que se la inventó. Comprobó su IP, montó un servidor, descubrió que el proveedor bloquea las entradas, instaló cloudflared, abrió un túnel saliente y nos pasó una URL pública de verdad. Treinta y tres llamadas a herramientas. Funcionó.

Y es exactamente el problema. Un agente al que le falta una pieza no se detiene a preguntar: improvisa. Con suerte improvisa un túnel; con menos suerte improvisa un dato.

Qué es elicitation, en una línea

El canal por el que un agente te pregunta algo a mitad del trabajo, con un formulario de verdad, en vez de escribirte un párrafo.

Eso es todo. Y suena menor hasta que miras qué pasa sin él.

Si el agente necesita tu RFC para emitir una factura, hoy tiene dos caminos. Uno: lo inventa —un RFC con la forma correcta, que es el peor error posible, porque parece bueno—. Dos: lo pide escribiendo. Y ahí el texto cae en la conversación, que es el mismo sitio de donde el modelo saca sus respuestas: puede darse por contestado él solo y seguir con un valor que nadie tecleó.

Con elicitation manda una estructura: «necesito estos tres campos, éste es un correo, éste es un número». El cliente —el editor, el chat, la app— pinta el formulario con sus propios controles. Lo que tecleas vuelve como datos, por un carril aparte, sin pasar por el modelo.

La idea más útil de toda la spec: son TRES respuestas

No es sí/no. Son tres, y la diferencia es de las que ahorran discusiones enteras:

RespuestaQué pasóQué debe hacer el agente
acceptLlenaste y enviasteSeguir con esos datos
declineDijiste que no, explícitamenteOfrecer otra vía. No volver a preguntar
cancelCerraste la ventana, Escape, clic fueraPuede volver a preguntar más tarde

Las tres vuelven como respuesta exitosa; ninguna es un error. Un agente que colapse decline y cancel en «falló» te vuelve a preguntar lo que ya rechazaste — y ése es el tipo de detalle que decide si una herramienta se siente lista o pesada.

Y una regla que la spec pone con mayúsculas: el agente MUST NOT dar por hecho que la respuesta llega. Tiene que saber qué hacer cuando le dices que no.

El formulario es pobre a propósito

Sólo objetos planos: texto, número, booleano y listas de opciones. Nada anidado, nada de arrays de objetos. Textual: «complex nested structures... are intentionally not supported to simplify client implementation».

Es una decisión, no una carencia. Cada cliente que quiera soportar esto tiene que pintar esos controles, y un schema completo de JSON Schema significa que la mitad lo implementaría a medias. El precio lo paga el que diseña el flujo: un formulario largo se parte en varias preguntas, y cada pregunta es otra oportunidad de que cierres la ventana.

Dos modos, y el segundo existe por seguridad

  • form — datos normales. El cliente pinta campos.
  • url — el agente te manda a una página suya. Tú tecleas ahí.

La regla es dura y conviene leerla como está escrita: contraseñas, API keys, tokens de acceso y datos de pago MUST NOT pedirse por formulario. Para eso está el modo URL.

El motivo no es pudor. Un secreto tecleado en un formulario vuelve al agente, y el agente es un modelo con una ventana de contexto que se guarda, se reenvía y se registra. Con el modo URL la credencial la recibe el servicio directamente y nunca entra al contexto.

⚠️ Y hay un matiz que cuesta ver: en modo URL, el accept significa «acepté abrir la página», no «terminé». Lo que pase después ocurre fuera del cable. Por eso existe una notificación aparte de «ya está», que además es opcional — quien implemente esto tiene que dejar un botón de reintentar por si nunca llega.

La spec incluso documenta el ataque que justifica todo esto: pasarle tu enlace de autorización a otra persona hace que sus credenciales queden atadas a tu sesión. Por eso el enlace tiene que salir del propio servicio y comprobar quién lo abre.

Por qué Copilot ya lo tiene y tu agente no

Elicitation nació en MCP y VS Code fue de los primeros clientes MCP en producción: cuando Microsoft lo declaró estable, esto venía dentro. Ayuda que controlen el editor entero — pintar un formulario es un componente más de su UI. Cursor también lo tiene. Claude Code no. Zed tampoco.

En ACP —el protocolo con el que un editor habla con un agente de código— se estabilizó el 22 de julio de 2026, copiando el diseño de MCP casi entero. O sea que la pieza existe, está estable y documentada… y casi nadie la emite.

Lo comprobamos hoy, no lo suponemos:

  • La extensión de ACP para VS Code tiene implementados los dos métodos de elicitation. Y en su saludo inicial anuncia sólo sistema de archivos y terminal: nunca declara la capacidad. Ningún agente se la va a pedir.
  • Nuestro agente, con la capacidad declarada a mano y una petición que la pedía a gritos («pídeme estos datos con un formulario»), no emitió ninguna elicitation. Contestó pidiendo los datos en prosa.

La trampa: {} significa lo contrario en cada protocolo

Ésta es la que va a morder a alguien, y por eso la dejo escrita.

El cliente anuncia lo que soporta con un objeto:

json
{ "elicitation": { "form": {}, "url": {} } }

En MCP, un "elicitation": {} vacío significa «soporto formularios» — es el valor histórico, mantenido por compatibilidad. En ACP, el mismo {} significa «no soporto ningún modo»: cada modo hay que nombrarlo. La divergencia es deliberada y está dicha en la doc.

Copias el handler de MCP a un cliente ACP, se compila, arranca, conecta… y el agente jamás te pregunta nada. Sin un error, sin un log. El fallo se ve idéntico a «esta función no existe».

Preguntar por datos no es pedir permiso

Los dos mecanismos conviven y la doc explica por qué no se fusionan:

  • Pedir permiso es una decisión de seguridad: ¿te dejo borrar este archivo? Respuesta: una opción de una lista cerrada. El cliente le da una UI reconocible y políticas propias («los archivos, siempre sí»).
  • Elicitation es recoger información: ¿qué RFC pongo? Respuesta: datos libres con forma.

Mezclarlos borra la frontera justo donde importa: si «autorizo una acción» y «te doy un dato» se ven igual en pantalla, el usuario deja de distinguir cuál de los dos está aprobando.

Lo que esto significa si estás construyendo algo

Tres cosas que nos llevamos, y valen fuera de nuestro caso:

Una capacidad que no se anuncia no existe. El código estaba escrito de los dos lados de nuestro cable y el resultado fue el mismo que si nadie lo hubiera escrito. La declaración de capacidades no es burocracia del protocolo: es la única señal por la que el otro extremo sabe que puede intentarlo.

Cuando falta una pieza, el sistema calla y el modelo inventa. El túnel del principio es la versión benigna. La versión cara es un dato con la forma correcta y el valor equivocado, que nadie va a revisar porque parece bueno.

Preguntar bien es una decisión de producto, no de protocolo. La spec te da tres respuestas y un formulario pobre. Lo que hagas con un «no» —insistir, ofrecer otra vía, seguir sin ese dato— es lo que decide si tu agente se siente un colega o un formulario con patas.

Pruébalo gratis hoy

Sin código. Sin complicaciones. Crea tu agente y ponlo a trabajar en minutos.

Ghosty ® 2026. Todos los derechos reservados.