Skip to main content
Glama

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 before

Nueve 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 verify rechazó

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; compile_app no escala

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 distill.js

en usoPIONEER_JUDGE_MODEL establecido: la pasada de verify en vivo anterior fue juzgada por el codificador ajustado, 8/9, cada veredicto en 106–183 ms

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 createIssue, no btn_submit_2

en usoground.js se ejecuta antes de la primera semilla; es aditivo a la tabla integrada, se guarda en caché por host, solo CLI

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:

  1. 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.

  2. 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.

  3. upload / trainPOST /felix/datasets/upload/url → PUT prefirmado → POST /felix/training-jobs, fastino/gliner2-base-v1, LoRA, 12 épocas. Entrena en unos cuatro minutos.

  4. 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 91370379…)

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 credential

Aplicació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:latest

Comando

Qué hace

npm run doctor

Qué credenciales funcionan, qué objetivos están activos

npm run compile

Explorar → sintetizar → emitir

npm run verify

Reproduce cada herramienta en frío; solo sobreviven las que pasan

npm run watch

Verificación continua con reparación automática

npm run score

Recuperación y precisión contra la API real del objetivo

npm run serve

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 verify

Variable

Valor por defecto

Significado

APIC_OUT_DIR

generated

Dónde viven los paquetes compilados. APIC_GENERATED se acepta como alias

APIC_APP

vikunja

Qué paquete dentro de él

TARGET_URL

http://localhost:3456

La aplicación que se está compilando

TARGET_USER / TARGET_PASS

apic / —

Credenciales para el objetivo

TARGET_LOGIN_PATH

descubierto

Solo se necesita cuando el formulario de inicio de sesión no está en una ruta tipo /login

APIC_SEEDS

/projects,/labels

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 compile

Salida 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.js

src/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

Playwright MCP

Automatización de navegador como herramientas MCP tipadas

Verbos genéricos (click(ref)) frente a sustantivos específicos de la app (createTask(title)). Tiempo de ejecución frente a tiempo de compilación

Apify MCP Server

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

Apify AI Web Scraper

URL + inglés sencillo → datos estructurados

Devuelve datos, no una interfaz, y re-ejecuta el LLM en cada llamada

cli-printing-press

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

Easy MCP

Especificación OpenAPI → herramientas MCP

Requiere que la API ya exista

Alita

El agente genera y reutiliza MCPs por tarea

Genera herramientas buscando en la web. apic las deriva operando el software

WebMCP

Las páginas declaran sus propias herramientas en JavaScript

Requiere que los desarrolladores de la aplicación lo adopten

Voyager

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_app ejecuta un pipeline reducido. compile.js es la compilación en proceso que llama el servidor MCP, y es cli.js menos 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 desde cli.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 donde npm run compile produce 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 collect contra un segundo objetivo es cómo obtenerlo.

  • El segundo objetivo compila de forma escasa. Gitea ahora compila de extremo a extremo — createRepository y createIssue, ambos verificados, 2/13 en su porción de issues contra swagger.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 de cli.js a la configuración, donde APIC_SEEDS ya vivía. Las acciones de etiquetas y comentarios aún se pierden: están detrás de controles que el vocabulario no nombra, y h no 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.

  • markTask falla 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. Cualquier npm run verify en 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 un APIC_SESSION distinto 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 deleteProject empieza 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

A
license - permissive license
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

  • 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.

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/brwbo/apic'

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