Publicaciones
Por qué construimos un servidor MCP nativo para retros

Kelly Lewandowski
Última actualización 19/05/20267 min de lectura
"Nativo" no significa "código distinto"
/api/v1/ a los que cualquiera con un token de acceso personal puede llamar directamente. Los mismos handlers, los mismos esquemas Zod, los mismos chequeos de permisos. Si cambiamos una regla en uno, el otro se mueve con él.Decisión 1: menos herramientas, con toggles en lugar de pares
retro_create_reaction y un retro_delete_reaction, igual que nuestras rutas REST separan create de delete. Dos herramientas por cada reacción con emoji. Multiplica eso entre ítems y comentarios y estás gastando tokens reales en ruido antes de que el modelo haya hecho algo útil.retro_toggle_reaction es una herramienta que activa o desactiva un emoji según si quien llama ya ha reaccionado o no. Devuelve "added" o "removed" en la respuesta, para que el modelo pueda narrar lo que pasó sin guardar ids de reacciones que solo necesitaría para llamar a delete.Decisión 2: escribir pistas dentro de las descripciones, no en la documentación
userId y un kudoType y devolvía un error amigable si pasabas a alguien que no estaba en el espacio. Los modelos se inventaban consistentemente un user id, recibían el error, pedían perdón y le pedían al usuario que pegara el id correcto. Inútil.retro_create_item si no existe ninguno). El
receptor debe ser miembro del espacio de la retro — usaorganization_list_users (admite un filtro de búsqueda) para buscar
el id de usuario por nombre.organization_list_users con el nombre que el usuario dijo en voz alta, obtiene el id y da los kudos de un tirón. El handler no cambió. La pista sí.
retro_update avisa dentro de la descripción que eliminar una columna también elimina todos los ítems que contiene. retro_cast_item_vote menciona explícitamente el tope de votos por tablero y por columna para que el modelo pueda avisar al usuario antes de chocar contra el 400. Cada "tienes que saber esto para llamarme correctamente" va dentro de la herramienta, no en una guía aparte que nadie lee.Decisión 3: una herramienta de búsqueda semántica, no una cadena de list-and-filter
retro_list, luego a retro_list_items por cada resultado, y se los lea todos al contexto. Eso es una tormenta de llamadas a herramientas que le cuesta dinero al usuario y produce una respuesta peor que un grep.search que ejecuta búsqueda semántica en todo el espacio a la vez. Devuelve ítems de retros, comentarios, action items, respuestas de standup, respuestas de encuestas, respuestas de ice-breakers y notas, ordenados por similitud coseno respecto a la consulta y agrupados por tipo. El modelo recibe los 20 resultados relevantes en una sola llamada en lugar de abanicarse sobre cientos de registros.Decisión 4: consentimiento por funcionalidad en el OAuth
Qué significa esto en el tablero de retro
Pre-cargar el tablero
"Abre la retro de este sprint y añade ítems a partir de los postmortems que escribimos en Linear esta quincena, uno por incidente, en la columna Qué Podría Mejorar." El modelo crea los ítems, los marca como anónimos donde el ticket de origen lo era, y se detiene. Encontrar contexto de retros antiguas
"¿Hemos hablado antes de la inestabilidad del CI?" La búsqueda semántica devuelve las tres retros donde apareció y los action items que salieron de ellas, en una sola llamada. Convertir discusión en action items
"Crea action items a partir de los tres ítems más votados del tablero, asígnalos a quien escribió cada uno, con fecha para el viernes." retro_list_itemsseguido de unas cuantas llamadas aaction_item_create. El modelo hace la asignación a partir del autor del ítem.Dar kudos por nombre
"Dale kudos a Priya por desatascar la migración." El modelo llama a organization_list_userscon una búsqueda por "Priya", y luego adjunta los kudos.
Lo que volveríamos a hacer y lo que nos saltaríamos
retro_get. Los modelos pasaban a resumir el resumen, y la latencia se triplicó. Ganó lo aburrido. La herramienta MCP devuelve la misma forma que devuelve el endpoint REST. La IA encima de eso es para que el usuario opte por ella vía prompt, no para que la horneemos en el protocolo./api/v1/. El trabajo interesante está en las definiciones de las
herramientas: nombres, agrupación, pistas y qué acciones se colapsan en un único
toggle. La lógica de backend es compartida.retro_create_item acepta un flag anonymous, y
retro_create_item_comment también. Cuando se activa, la
respuesta omite el id del usuario autor, igual que hace la interfaz. El
anonimato se aplica a nivel del handler, no en la descripción.retro_update avisa de que
eliminar una columna también elimina todos los ítems que contiene. Confiamos
en que el modelo se lo plantee al usuario antes de llamarla, igual que un
desarrollador leyendo la documentación se fijaría en el aviso. No hay un
paso de confirmación aparte dentro del protocolo.