apic
apic
Un compilador de app a API. Apúntalo a una app web que no tenga API para agentes. Un agente de uso de ordenador explora la interfaz, verifica lo que encuentra ejecutándolo y emite un servidor MCP tipado para la app.
Playwright MCP interpreta la app en cada llamada. apic la compila una vez.
Construido en solitario en un día en el {Tech: Europe} × VEED Hackathon, Londres, 22 de agosto de 2026.
→ apic-ui.vercel.app — el vídeo de demostración está ahí, junto con lo que decide cada modelo colaborador y lo que midió el compilador.
Sitios de consumo públicos
apic --read https://example.com compila la superficie pública de solo lectura de cualquier sitio de consumo en herramientas MCP. Empieza en ese sitio (más semillas opcionales del mismo sitio), descubre cuadros de búsqueda, filtros y tarjetas de resultados repetidas, y luego emite solo las herramientas cuyas filas sobreviven a una reproducción en frío. No asume rutas de Deliveroo, vocabulario de restaurantes, una cuenta, una cesta ni un proceso de pago.
Para una página conocida de colección/artículo, pásala explícitamente como semilla directa del mismo sitio: APIC_READ_DIRECT_URL=https://example.com/catalog/item apic --read https://example.com. Las URLs proporcionadas por el agente se limitan al origen compilado en la receta.
Un prompt, sin URL objetivo
Cuando APIC está conectado como su servidor MCP, usa fulfill_request en lugar de compile_app para una pregunta de consumo normal:
{ "request": "Find me the cheapest pizza near 17 & 18 Clere Street" }El servidor usa Tavily para encontrar servicios candidatos públicos, OpenAI para seleccionar y operar el flujo compilado, h para priorizar controles de lectura ambiguos, Pioneer para clasificar si las sondas sacaron a la luz resultados significativos, y fal solo donde esa clasificación necesita un arbitraje visual. Prueba un pequeño conjunto de respaldo de origen distinto si un candidato está bloqueado o no tiene un flujo público reproducible. Nunca inicia sesión, hace pedidos, finaliza compras ni evita un desafío. Las herramientas supervivientes se verifican en frío, se devuelven como evidencia y se registran en el mismo servidor MCP para llamadas posteriores.
Related MCP server: mcp-apps-demo-engine
Demo
Míralo en el sitio: apic-ui.vercel.app — dos minutos, sin editar: la compilación, las herramientas generadas apareciendo en una sesión en vivo, y el watcher detectando un cambio de interfaz por sí solo.
El mismo sitio contiene los números que reporta este README, el desglose por colaborador y el fragmento de instalación para cada cliente MCP.
El problema
Los agentes de uso de ordenador no escalan económicamente. Cada ejecución vuelve a derivar el mismo conocimiento de los píxeles: un viaje de ida y vuelta del modelo por paso, una instantánea de página por paso que llena la ventana de contexto, y una fiabilidad que se degrada de forma compuesta a lo largo de una cadena. Por eso se demuestran constantemente y se despliegan raramente.
El software que los agentes más necesitan manejar es exactamente el software con menos probabilidades de tener alguna vez una API: herramientas internas, sistemas heredados, cualquier cosa cuyo proveedor ya no existe. No puedes esnifar una pestaña de red que no tiene nada, y no puedes pedirle a una app de línea de negocio de 2011 que adopte un protocolo nuevo.
apic usa al agente caro una vez, para escribir la interfaz. Después es una llamada a función.
Cómo funciona
Etapa | Qué hace | Tecnología |
Ground | Lee la documentación propia del objetivo y aprende los sustantivos de esa app, para que el vocabulario no esté codificado de forma fija al de Vikunja | Tavily + OpenAI, cacheado por host — solo ruta CLI |
Explore | Maneja la app, clasifica las affordances para que las acciones de creación vayan primero, abre formularios y los envía | Playwright + h (nivel de escalada para controles que el vocabulario no puede nombrar) |
Perceive | Decide si cambió algo significativo | diff de DOM, escalando a fal en la ruta CLI |
Synthesise | Convierte una trayectoria en un esquema de herramienta tipado | determinista — sin llamada de modelo |
Verify | Reproduce la herramienta en frío con argumentos que la app nunca ha visto | suelo de diff sin claves, luego el juez Pioneer afinado, con OpenAI en espera |
Emit | Escribe un servidor MCP ejecutable, sus esquemas y su evidencia | — |
Watch | Vuelve a ejecutar la suite en un intervalo | — |
Heal | Una herramienta en rojo vuelve a entrar en el descubrimiento en su propia semilla | — |
La ruta de reparación es la ruta de construcción. La curación no parchea un selector: vuelve a ejecutar el descubrimiento que encontró la herramienta en primer lugar y hace coincidir por el nombre que produce la síntesis. Un botón renombrado sigue produciendo createProject.
Una herramienta existe solo si la app confirmó la escritura
Contar nodos del DOM produce una herramienta de aspecto plausible para cada botón de la página. apic emite una solo cuando la propia app afirma que el estado cambió, mediante tres señales que cubren tres comportamientos distintos de la app:
Comportamiento | Ejemplo | Señal |
anunciar-y-quedarse | crear una etiqueta | banner de éxito en una región de estado |
anunciar-y-navegar | crear un proyecto | el banner sobrevive al cambio de URL |
añadido silencioso | añadido rápido de kanban | el valor enviado aparece como contenido renderizado |
reubicación | arrastrar una tarjeta entre columnas | la tarjeta cambió de contenedor |
La reubicación importa porque un arrastre no tiene banner y no hace eco de nada: la tarjeta ya existía. El cambio de contención es la evidencia, y ningún re-renderizado cosmético puede producirlo.
Las recetas se vinculan a la identidad, no a la ubicación
Vikunja regenera los ids de los elementos en cada carga de página, así que un selector almacenado llega muerto. Una receta registra lo que un campo es — su etiqueta, placeholder, nombre — y la reproducción lo re-resuelve en vivo, recurriendo a una cadena de selectores estable-primero (name → id estable → placeholder → id generado al final).
Resultados
Compilado desde la interfaz. La especificación OpenAPI del objetivo nunca se lee durante la compilación — se usa solo como verdad de referencia para la puntuación, que es por lo que el número de recall significa algo.
El denominador, declarado antes del número: 18 es cada operación de escritura (POST/PUT/DELETE) en /projects, /tasks y /labels en la propia especificación OpenAPI de Vikunja, tras eliminar lo que no es un gesto de tablero: equipos, permisos a nivel de proyecto, compartir enlaces, adjuntos, relaciones de tareas, duplicación, endpoints masivos y recibos de lectura. Vikunja publica 105 operaciones de escritura en total; 18 es el subconjunto que una persona puede realizar en un tablero Kanban, y cada herramienta emitida puede reclamar como máximo una de ellas, así que el recall no puede inflarse con coincidencias laxas.
RECALL 8/18 of the board write-ops in the target's own API
PRECISION 9/9 emitted tools that map to a real operation
VERIFIED 9/9 survived a cold replay with arguments never seen beforeNueve herramientas descubiertas, nueve servidas. Las herramientas rechazadas no se eliminan: permanecen en tools.json con verified: false, porque una herramienta rechazada es evidencia sobre el compilador, no basura.
markTask es inestable y eso vale más que el 9/9. Dos ejecuciones de verificación consecutivas contra el mismo paquete, sin cambios en medio, dieron 8/9 y luego 9/9: falló con "mutación observada pero nada confirmó una escritura" y luego pasó con "Éxito: la tarea se guardó correctamente." La causa probable es el estado de la tarea sembrada: si aterrizas en una ya hecha, el control lee MARCAR COMO NO HECHA y confirma de forma distinta. No toma parámetros, así que tampoco puede desambiguar por argumento.
Ese es un ejemplo en vivo del problema flake-vs-drift listado abajo como no resuelto: watch contaría ese fallo como drift y llamaría a heal, cuando no se desvió nada en absoluto.
Verificación continua durante una tarde en vivo:
327 checks · 118 breaks · 3 automatic repairs · MTTR 20s(out/watch-stats.json, 38 ciclos desde las 11:33 BST, aún en ejecución mientras se escribía esto: los contadores se mueven.)
Lee ese recuento de roturas como lo que es. stats.breaks++ se dispara en cada reproducción en rojo en cada ciclo, así que tres herramientas que permanecen en rojo durante 38 ciclos se leen como ~114 roturas: es un recuento de herramienta-en-rojo-por-ciclo, no 118 eventos de drift separados. Y este watcher se inició a las 11:33, antes de la corrección de heal(), que devolvía una receta reparada sin el provenance fresco por el que realmente hace clic el abridor de replay(); por tanto, una herramienta cuyo control había sido renombrado se curaba en cada ciclo y no se ponía en verde en ninguno. Eso es la mayor parte del 6/9. Corregido en el código, no re-recopilado en una ventana comparable.
Tecnologías colaboradoras
Cada una tiene una etapa, y cada una se degrada en lugar de bloquear: todo el pipeline se ejecuta sin ninguna clave de API, con fidelidad reducida. Esa propiedad es por la que el compilador se pudo construir antes de que llegara ninguna credencial — y también es por la que una integración puede dejar de contribuir sin que la compilación lo note, que es lo que registra la columna de estado.
Tech | Stage | Why it earns its place | Status |
OpenAI | Verify | Un veredicto independiente sobre si el efecto previsto se produjo, superpuesto al suelo de diff sin claves. Puede mantener un rechazo, nunca revocarlo. | en uso — se pronunció sobre la única herramienta que |
fal | Perceive | VLM rápido para el juicio significativo-vs-estético, al que se escala solo cuando el diff del DOM es ambiguo | en uso — 4/4 pasos escalados juzgados en la última compilación, 2 de ellos considerados estéticos. Solo en CLI; |
Pioneer | Verify, Distil | Un codificador GLiNER2 ajustado con la propia evidencia de verificación de apic sustituye al juez GPT-4.1-mini — y le gana en herramientas reservadas (abajo). También el clasificador de texto de diff en | en uso — |
h | Explore | Lee la página y nombra las acciones de escritura que el vocabulario sin claves rechazó | en uso — se ejecuta una vez por semilla sobre los restos; nombra 0 de 3 en Vikunja, correctamente |
Tavily | Ground | Documentación de la app → vocabulario de dominio, para que las herramientas se llamen | en uso — |
La división en dos niveles es la propia tesis del producto aplicada a sí mismo: fal es la capa de percepción barata y de alta frecuencia; OpenAI es la capa de razonamiento cara y de baja frecuencia. Escalar ante el fallo, no en cada llamada.
Cómo se llama a cada uno en la práctica
h — holo3-1-35b-a3b, api.hcompany.ai/v1 (compatible con OpenAI).
gesture() asigna el texto visible de un control a un par <verbo, recurso> con
expresiones regulares y devuelve null para todo lo demás. Ese null es la barrera de
precisión y también donde se pierde la recuperación: un botón de solo icono, un
control que no empieza con un verbo, o una app cuya redacción el vocabulario nunca
anticipó se descartan por muy claro que escriban. h es el nivel de escalado para
exactamente ese conjunto — discover.js classify() envía un JPEG de la página y
los controles rechazados, una vez por semilla, y pregunta cuáles escriben.
Tres cosas evitan que eso cueste precisión. Las respuestas se validan contra el
vocabulario cerrado — seis verbos, cuatro recursos — mediante plan.gestureFrom(),
de modo que un verbo inventado no puede nombrar una herramienta. Los controles fuera de
la franja se retienen en lugar de ofrecerse, porque excluir AÑADIR A FAVORITOS es una
decisión de alcance y no un vacío que un modelo deba llenar. Y un control clasificado
aún debe hacer que la app confirme una escritura como cualquier otro candidato.
Medido, en la compilación que informa este README: h lee los tres controles que el vocabulario deja sin resolver en la página de tareas de Vikunja y nombra uno de ellos — un control de solo icono que las expresiones regulares descartan por completo:
! h read 3 unresolved controls, named 1
! h: "Kanban bucket: To-Do" -> move task (Pencil icon allows changing task status)Ese es el nivel de escalado haciendo el trabajo para el que existe: un control sin verbo principal y sin texto utilizable, recuperado de su icono y asignado al vocabulario cerrado.
No añadió una herramienta, y no afirmamos que lo hiciera. move task ya se
había encontrado dos veces para entonces — una por el arrastre del tablero (Move card between columns), otra por el desplegable de cubo de la página de tareas (Kanban bucket: Doing) —
así que la respuesta de h se deduplicó en el moveTask que produjo el arrastre. En este
objetivo, h es corroboración, no recuperación: una tercera ruta independiente a una acción
a la que otras dos rutas ya habían llegado. Una revisión anterior de este archivo decía que h
nunca se alcanzaba y no nombraba ninguna; ambas cosas eran falsas.
Si h añade recuperación no se prueba aquí, porque las escrituras de Vikunja están inusualmente bien etiquetadas. El caso para el que está construido — una app cuyos botones son iconos — es exactamente el caso que este objetivo no presenta. Sin la clave, la compilación pierde esa corroboración y nada más.
fal — google/gemini-2.5-flash-lite vía fal-ai/any-llm/vision.
El diferenciador de DOM dice si la página cambió. No puede resolver un cambio que el
texto no describe — una tarjeta que cambió de columna, un control que simplemente se
iluminó. perceive.js adjudicate() escala esos pasos,
y solo esos, a píxeles.
Medido, de la última compilación completa: vision: 4/4 pasos escalados juzgados por fal, 1 arrastre corroborado, 2 considerados estéticos. Los dos veredictos estéticos son la
mitad interesante — fal eliminando candidatos que de otro modo se habrían
sondeado como escrituras. Se ejecuta desde cli.js; una compilación impulsada a través de compile_app
en el servidor MCP no escala.
OpenAI — gpt-4.1-mini, salida estructurada.
verify.js reproduce cada herramienta emitida en frío con argumentos que la
app nunca ha visto, y juzga el resultado dos veces: primero un suelo de diff determinista,
luego el modelo. El modelo puede mantener un rechazo y nunca revocar uno —
una herramienta que el diff no pudo confirmar permanece rechazada por muy segura que esté el juez.
Medido: en la ejecución donde markTask falló, su registro dice
openai/gpt-4.1-mini disagreed but cannot overturn a rejection. Esa asimetría
es deliberada: un juez que puede promocionar sus propias conjeturas es una fuga de precisión.
Pioneer — GLiNER2 (fastino/gliner2-base-v1), un POST /inference por paso.
distill.js envía el texto de diff de cada paso en su propia solicitud
y recibe una clase de cambio de estado, un indicador de destructividad y los sustantivos de
dominio, por encima de un umbral de confianza de 0,6. Antes agrupaba toda la trayectoria,
y el agrupamiento es de lo que trata la tercera lección ganada con esfuerzo a continuación:
el mismo texto puntuó creation 0,777 solo, creation 1,000 en la posición 0, y DELETION 0,600 en
la posición 2 del lote invertido — una etiqueta incorrecta que supera el umbral. Un id de trabajo de entrenamiento completado en
PIONEER_MODEL intercambia el codificador base por un punto de control ajustado con las propias
etiquetas de apic — el sistema compilando su propia capa de percepción — y nada más
cambia.
Pioneer — el juez de verificación ajustado. Esta es la entrada del desafío paralelo de Pioneer:
ajustar un modelo que supere o reemplace una llamada a una API de LLM de propósito general.
La llamada que reemplaza es judgeModel() en
verify.js — GPT-4.1-mini, un mensaje de sistema de 200 palabras,
salida estructurada, una pregunta por herramienta reproducida: dado este diff de DOM, ¿la
escritura prevista ocurrió de forma demostrable? Eso es una clasificación de texto de dos
etiquetas disfrazada de chat de completado.
pioneer-train.js construye el reemplazo a partir de los
propios datos de escape del producto, sin etiquetado manual:
collect — reproduce cada herramienta compilada seis veces con argumentos nuevos a través de
verifyAll(), registrando la evidencia y el veredicto que el juez publicado (suelo de diff + GPT) le dio. 54 filas reales.dataset — deriva negativos eliminando la evidencia en la que se basa el suelo (banner desaparecido, eco movido a la entrada que lo escribió, argumento sin rellenar, la reproducción lanzó un error, nada cambió) y positivos que conservan la etiqueta (orden de nodos invertido, nodos no relacionados añadidos, argumentos renombrados a valores que una persona escribiría). Cada fila derivada es reetiquetada por el mismo suelo determinista. 788 filas; reservadas por herramienta, por lo que el banco de pruebas mide herramientas que el codificador nunca ha visto.
upload / train —
POST /felix/datasets/upload/url→ PUT prefirmado →POST /felix/training-jobs,fastino/gliner2-base-v1, LoRA, 12 épocas. Entrena en unos cuatro minutos.bench — las filas reservadas a través de ambos jueces. El LLM se llama a través de la
judgeModel()sin cambios, por lo que ve exactamente lo que ve en producción.
juez | exactitud | precisión | recuperación | falsos pos | falsos neg | ms/fila |
Ajuste de Pioneer GLiNER2 (trabajo | 94,4 % | 100 % | 87,6 % | 0 | 12 | 150 |
OpenAI GPT-4.1-mini | 89,3 % | 84,3 % | 93,8 % | 17 | 6 | 890 |
215 filas reservadas, dos herramientas (createTask, assignLabel) ausentes del entrenamiento.
El codificador sacrifica algo de recuperación por cero falsos positivos — la compensación correcta
para este juez, que por diseño puede mantener un rechazo pero nunca promocionar una
conjetura. Establece PIONEER_JUDGE_MODEL al id del trabajo y verify lo usa; OpenAI
permanece en espera como respaldo, y sin claves el suelo aún se ejecuta.
Tres lecciones aprendidas a la fuerza, todas verificadas en vivo y registradas en el código:
multi_label/top_k dentro de una especificación de clasificación hacen que la ruta
unificada /inference devuelva categories: [] para cada texto (esto, no el crédito,
es por lo que la etapa de destilación estuvo en silencio toda la mañana); GLiNER2 se entrena
solo como LoRA — training_type: "full" se acepta y falla dentro de Modal sin línea de
registro; y la inferencia por lotes (text: [...]) en un modelo ajustado devuelve etiquetas que
no se alinean con las entradas, por lo que el juez envía un texto por solicitud.
Tavily — api.tavily.com/search, cinco resultados, respuesta incluida.
ground.js se ejecuta antes de la primera semilla. plan.js incluye
los sustantivos de Vikunja — cubo, tarea, etiqueta, proyecto — y apuntando a cualquier otra cosa
a gesture() se le preguntan problemas y repositorios por una tabla que nunca ha oído
hablar de ellos, devuelve null, y el control se descarta. Tavily obtiene la
documentación del propio objetivo; OpenAI estructura esa prosa en un conjunto de sustantivos cerrado
bajo un esquema estricto; cada término se valida contra /^[a-z][a-z-]{1,18}$/,
con un máximo de 12, y se fusiona en la tabla integrada en lugar de reemplazarla,
por lo que la base puede añadir vocabulario y nunca puede quitar el de Vikunja. Se guarda en
caché por host en .apic/, por lo que una compilación repetida no cuesta nada y una demo no
depende del wifi del lugar.
Degrada en tres pasos — sin clave de Tavily, sin evidencia; sin clave de OpenAI, la
evidencia no se puede estructurar; nada sobrevive a la validación — y cada uno registra
y deja la tabla integrada en pie. Como fal, se ejecuta desde cli.js:
compile_app en el servidor MCP usa el vocabulario integrado.
Así que las cifras de recuperación anteriores se produjeron sin claves, con fal en los pasos de percepción escalados y un juez de OpenAI en la pasada de verificación. No son una demostración de la pila completa de socios, y este README no fingirá lo contrario.
Configuración
git clone https://github.com/brwbo/apic && cd apic
npm install && npx playwright install chromium
cp .env.example .env # fill in keys; .env is gitignored
npm run setup # starts the target app, checks every credentialAplicación objetivo (autohospedada, desechable — nunca apuntes esto al producto de un tercero):
docker volume create vikunja-files
docker run --rm -v vikunja-files:/data alpine sh -c "chown -R 1000:0 /data"
docker run -d --name vikunja -p 3456:3456 -v vikunja-files:/app/vikunja/files \
-e VIKUNJA_SERVICE_PUBLICURL=http://localhost:3456 \
-e VIKUNJA_DATABASE_PATH=/app/vikunja/files/vikunja.db \
-e VIKUNJA_RATELIMIT_ENABLED=false \
vikunja/vikunja:latestComando | Qué hace |
| Qué credenciales funcionan, qué objetivos están activos |
| Explorar → sintetizar → emitir |
| Reproduce cada herramienta en frío; solo sobreviven las que pasan |
| Verificación continua con reparación automática |
| Recuperación y precisión contra la API real del objetivo |
| Ejecuta apic en sí mismo como servidor MCP — ver más abajo |
Todos los comandos leen las mismas dos variables, de modo que una ejecución completa puede apuntarse a un paquete alternativo sin tocar el activo:
APIC_OUT_DIR=out/rescue APIC_APP=vikunja npm run verifyVariable | Valor por defecto | Significado |
|
| Dónde viven los paquetes compilados. |
|
| Qué paquete dentro de él |
|
| La aplicación que se está compilando |
|
| Credenciales para el objetivo |
| descubierto | Solo se necesita cuando el formulario de inicio de sesión no está en una ruta tipo |
|
| Páginas desde las que empezar a explorar |
Las semillas y el objetivo están controlados por el entorno — nada en el compilador conoce las rutas de Vikunja:
APIC_APP=gitea TARGET_URL=http://localhost:3001 APIC_SEEDS=/repo/create,/issues npm run compileSalida generada
generated/vikunja/ — servidor, esquemas y la evidencia
de cada herramienta. Nada en ese directorio fue escrito por un humano.
Úsalo como servidor MCP
claude mcp add apic -- node /path/to/apic/src/server.jssrc/server.js arranca con una herramienta, compile_app. Apúntala a una URL y
ejecuta el pipeline en proceso, emite generated/<app>/, registra las
herramientas compiladas sobre sí mismo y envía notifications/tools/list_changed — de modo que
se pueden invocar en la misma conexión, sin reiniciar. Desde un arranque en frío:
[apic] ready - 0 compiled tools + compile_app
BEFORE compile, tools/list = [ 'compile_app' ]
compile_app returned in 22.1s
list_changed notification: YES
AFTER compile = [compile_app, createProject, createLabel, updateLabel, createTask]
createLabel -> {"ok":true,"effect":"creation","expected":"creation"}Un compilador que necesita que reinicies lo que acaba de ampliar es un paso de construcción. Uno que no lo necesita es un compilador en vivo. Notas de compatibilidad con clientes y transcripciones completas: docs/mcp-client.md.
Ambos callejones sin salida se responden, no se notifican
Un cliente solo se encuentra con apic en el momento en que falta algo, y ambos momentos solían terminar la conversación.
Una herramienta que no existe devuelve la compilación que la crearía:
unknown tool: createIssue
No compiled tool exposes that action (compiled so far: vikunja). If the app has no API for it, make one:
compile_app { "url": "http://localhost:3456", "goal": "createIssue" }Una herramienta que la aplicación ha movido se repara en la ruta de la llamada —
watch sana con un temporizador, el servidor sana bajo demanda, a través del mismo
heal(). La herramienta se pone en rojo, el compilador re-explora esa única acción, la
reparación se escribe de vuelta en tools.json y la llamada se reintenta antes de que el
llamante vea un fallo:
[apic] createLabel is red (no control matched "ADD LABEL (RENAMED)") - re-exploring to heal it
[apic] createLabel healed in 13.6s (click "…" -> "create label"; selectors re-resolved); retry passed
{ "ok": true, "effect": "creation", "healed": { "ms": 13589, "persisted": true } }Una herramienta sana no se ve afectada por nada de esto: misma llamada, 4,4 s, sin re-exploración.
Trabajo relacionado y en qué se diferencia
Proyecto | Qué hace | La diferencia |
Automatización de navegador como herramientas MCP tipadas | Verbos genéricos ( | |
Genera automáticamente herramientas tipadas a partir de esquemas de entrada de Actor | Los Actores están escritos por humanos — genera el envoltorio a partir de un contrato escrito por humanos | |
URL + inglés sencillo → datos estructurados | Devuelve datos, no una interfaz, y re-ejecuta el LLM en cada llamada | |
URL/HAR/OpenAPI → CLI + servidor MCP, con compuertas de verificación | Olfatea el tráfico de red — la aplicación ya debe tener una API. apic maneja la interfaz de usuario | |
Especificación OpenAPI → herramientas MCP | Requiere que la API ya exista | |
El agente genera y reutiliza MCPs por tarea | Genera herramientas buscando en la web. apic las deriva operando el software | |
Las páginas declaran sus propias herramientas en JavaScript | Requiere que los desarrolladores de la aplicación lo adopten | |
Escribe una habilidad, verifícala, guárdala, reutilízala | El ancestro del bucle verificar-y-conservar |
El bucle no es novedoso — de dónde viene la capacidad sí lo es. Alita lee internet para hacer herramientas; cli-printing-press lee la red; Easy MCP lee una especificación. apic lee la aplicación.
Lo que aún no funciona
Dicho sin rodeos, porque un compilador que oculta sus modos de fallo no es un compilador.
h está en la ruta y no contribuye nada en este objetivo. Lee los controles que el vocabulario rechazó y no nombra correctamente ninguno de ellos, porque la porción del tablero de Vikunja ya está cubierta por las expresiones regulares. La escalada es real y medida; la ganancia es cero aquí, y un objetivo cuyos controles son iconos en lugar de frases verbales es el caso que lo demostraría.
compile_appejecuta un pipeline reducido.compile.jses la compilación en proceso que llama el servidor MCP, y escli.jsmenos cinco cosas: anclaje (Tavily/OpenAI), descubrimiento de semillas, la sonda dedicada de páginas de formulario, la semilla de detalle de tarea y el arrastre de Kanban, más el nivel de visión de fal —adjudicate()se ejecuta solo desdecli.js. Conserva el descubrimiento, la persistencia, la destilación de Pioneer, la síntesis y la emisión. Por eso la transcripción anterior muestra cuatro herramientas dondenpm run compileproduce nueve: la demo del compilador en vivo y el paquete de 9 herramientas son dos rutas diferentes, y solo la del CLI es la que describen las cifras de recuperación.Pioneer parecía no disponible toda la mañana — primero
403 payment_method_required, y después de una nueva clave,categories: []en cada llamada, que el código interpretó como "sin opinión" y recurrió a la heurística. El segundo fue un error de forma de solicitud (multi_label/top_k), no de la API. Cada integración se escribió para degradarse silenciosamente, y cada una lo hizo — la degradación es el comportamiento previsto; no darse cuenta durante toda una mañana no lo es.El juez ajustado ha visto una sola aplicación. Sus 788 filas de entrenamiento son todas de Vikunja. La división de validación es por herramienta, no por aplicación; un banco de pruebas de Gitea o ParaBank es la siguiente prueba honesta, y
collectcontra un segundo objetivo es cómo obtenerlo.El segundo objetivo compila de forma escasa. Gitea ahora compila de extremo a extremo —
createRepositoryycreateIssue, ambos verificados, 2/13 en su porción de issues contraswagger.v1.json. No requirió ningún cambio en el descubrimiento: las dos correcciones fueron una clase de confirmación (Gitea confirma una escritura sirviendo el resultado en una URL nueva que lleva el valor enviado, y la compuerta solo buscaba banners y ecos del cuerpo) y mover los patrones de URL de contenedor/ítem fuera decli.jsa la configuración, dondeAPIC_SEEDSya vivía. Las acciones de etiquetas y comentarios aún se pierden: están detrás de controles que el vocabulario no nombra, yhno nombró ninguno de los 14 que se le dieron.8/18 de recuperación en Vikunja. Faltan: creación de cubos, comentarios, relaciones y adjuntos.
markTaskfalla aproximadamente una de cada dos ejecuciones (ver Resultados). El efecto es real y observado; si algo lo confirma depende del estado existente de la tarea. Cualquiernpm run verifyen vivo debería esperarse que imprima 8/9 o 9/9.Las ejecuciones concurrentes chocan. Cada comando comparte una sesión almacenada en
.apic/session.json, así que una compilación y una verificación iniciadas juntas pueden destruir el contexto del navegador de la otra a mitad de ejecución (Error setting storage state: Execution context was destroyed). Pasa unAPIC_SESSIONdistinto por ejecución como solución temporal; la solución real es un archivo de sesión por ejecución por defecto.Watch trata cada fallo como deriva. No existe una clasificación real de flake frente a deriva. Tres clases de falsos positivos se corrigieron a mano — limitación de velocidad, expiración de token y una página bloqueada — pero el problema general persiste.
El cambio semántico no se detecta y es peligroso. Si
deleteProjectempieza a archivar en lugar de eliminar, sanar el selector es la respuesta equivocada. La verificación comprueba que ocurrió un efecto, no que sea el mismo efecto.No hay acciones inversas, así que el conjunto contamina su propio fixture. Las ejecuciones repetidas degradan el objetivo hasta que se restablece.
La autenticación se evita. Un inicio de sesión, un usuario, sin ámbitos de permisos — que es la parte difícil del problema en el software empresarial real.
Declaración de trabajo previo
Escrito desde cero en el hackathon. Sin plantillas importadas; el repositorio se creó vacío la mañana del evento. Playwright, el SDK de MCP y los clientes de OpenAI y fal son las únicas dependencias.
Licencia
MIT
This server cannot be installed
Maintenance
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
- AlicenseCqualityAmaintenanceA production-grade MCP server that turns natural language intent into fully-architected, accessible, production-ready UI code through a 7-step agentic pipeline.201Apache 2.0
- FlicenseNot gradedqualityBmaintenanceAn extensible MCP server and generative UI engine for hosting interactive B2B enterprise workflows with dynamic styling and stateful simulators.
- FlicenseNot gradedqualityBmaintenanceThis MCP server renders UI design artifacts headlessly, runs deterministic linters, and manages stateful design review loops with an independent vision critic.
- FlicenseNot gradedqualityCmaintenanceA universal MCP server for registering internal, external, and OpenAPI-based APIs as MCP tools. It exposes them to MCP clients via Streamable HTTP and provides admin portal, RBAC/session auth, credential injection, and audit logging.
Related MCP Connectors
MCP server for secureFlows: token-free URL builders and integration-linting tools for AI agents.
MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.
Read-only MCP server for the WebAssembly spec: instructions, types, sections, search, proposals.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/brwbo/apic'
If you have feedback or need assistance with the MCP directory API, please join our Discord server