Skip to main content
Glama

apic

앱-API 컴파일러. 에이전트용 API가 없는 웹 앱을 가리키면 된다. 컴퓨터 사용 에이전트가 UI를 탐색하고, 실행을 통해 발견한 내용을 검증한 다음, 해당 앱용 타입이 지정된 MCP 서버를 생성한다.

Playwright MCP는 호출할 때마다 앱을 해석한다. apic은 한 번 컴파일한다.

{Tech: Europe} × VEED 해커톤에서 하루 만에 혼자 구축, 런던, 2026년 8월 22일.

apic-ui.vercel.app — 데모 영상이 거기에 있으며, 각 파트너 모델이 결정한 내용과 컴파일러가 측정한 내용도 함께 있다.

공개 소비자 사이트

apic --read https://example.com은 모든 소비자 사이트의 공개 읽기 전용 표면을 MCP 도구로 컴파일한다. 해당 사이트(선택적 동일 사이트 시드 포함)에서 시작하여 검색 상자, 필터, 반복 결과 카드를 발견한 다음, 콜드 리플레이에서 행이 살아남는 도구만 생성한다. Deliveroo 경로, 레스토랑 용어, 계정, 장바구니 또는 결제를 가정하지 않는다.

알려진 컬렉션/아이템 페이지의 경우 동일 사이트 직접 시드로 명시적으로 전달한다: APIC_READ_DIRECT_URL=https://example.com/catalog/item apic --read https://example.com. 에이전트가 제공한 URL은 레시피에 컴파일된 오리진으로 제한된다.

프롬프트 하나, 대상 URL 없음

APIC가 MCP 서버로 연결된 경우 일반 소비자 질문에는 compile_app 대신 fulfill_request를 사용한다:

{ "request": "Find me the cheapest pizza near 17 & 18 Clere Street" }

서버는 Tavily를 사용하여 공개 후보 서비스를 찾고, OpenAI를 사용하여 컴파일된 흐름을 선택하고 운영하며, h를 사용하여 모호한 읽기 컨트롤의 우선순위를 정하고, Pioneer를 사용하여 프로브가 의미 있는 결과를 표시했는지 분류하며, 해당 분류에 시각적 판정이 필요한 경우에만 fal을 사용한다. 후보가 챌린지에 직면하거나 재생 가능한 공개 흐름이 없는 경우 작은 오리진-구분 폴백 세트를 시도한다. 로그인, 주문, 결제, 챌린지 우회를 절대 하지 않는다. 살아남은 도구는 콜드 검증을 거쳐 증거로 반환되고, 이후 호출을 위해 동일한 MCP 서버에 등록된다.


Related MCP server: mcp-apps-demo-engine

데모

사이트에서 시청: apic-ui.vercel.app — 2분, 편집 없음: 컴파일, 라이브 세션에 나타나는 생성된 도구, 그리고 UI 변경을 스스로 감지하는 와처.

같은 사이트에는 이 README가 보고하는 수치, 파트너별 분석, 모든 MCP 클라이언트용 설치 스니펫이 있다.

문제

컴퓨터 사용 에이전트는 경제적으로 확장되지 않는다. 매 실행마다 픽셀에서 동일한 지식을 다시 도출한다: 단계마다 모델 왕복, 단계마다 컨텍스트 창을 채우는 페이지 스냅샷, 그리고 체인을 따라 아래로 복합적으로 악화되는 신뢰성. 그래서 끊임없이 데모되고 거의 배포되지 않는 것이다.

소프트웨어 에이전트가 가장 필요로 하는 것은 정확히 API를 제공할 가능성이 가장 낮은 소프트웨어다 — 내부 도구, 레거시 시스템, 공급업체가 사라진 모든 것. 아무것도 없는 네트워크 탭을 스니핑할 수 없고, 2011년산 업무용 앱에 새 프로토콜을 채택하라고 요청할 수 없다.

apic은 비싼 에이전트를 한 번만 사용하여 인터페이스를 작성한다. 그 후에는 함수 호출일 뿐이다.

작동 방식

단계

수행 내용

기술

기반 구축

대상의 자체 문서를 읽고 해당 앱의 명사를 학습하므로 어휘가 Vikunja에 하드코딩되지 않음

Tavily + OpenAI, 호스트별 캐시 — CLI 경로 전용

탐색

앱을 구동하고, 생성 작업이 먼저 가도록 어포던스를 순위화하고, 양식을 열고 제출함

Playwright + h (어휘가 이름을 붙일 수 없는 컨트롤용 에스컬레이션 계층)

인지

의미 있는 변경이 있었는지 결정함

DOM diff, CLI 경로에서 fal로 에스컬레이션

종합

궤적을 타입이 지정된 도구 스키마로 변환함

결정적 — 모델 호출 없음

검증

앱이 본 적 없는 인수로 도구를 콜드 리플레이함

키 없는 diff 기준선, 그 다음 미세 조정된 Pioneer 판정기, OpenAI 대기 상태

생성

실행 가능한 MCP 서버, 스키마, 증거를 작성함

감시

간격으로 스위트를 재실행함

치유

빨간 도구가 자체 시드에서 발견 단계로 재진입함

수리 경로는 빌드 경로다. 치유는 선택자를 패치하지 않는다 — 도구를 처음 발견한 발견을 재실행하고 이름 합성이 생성하는 결과와 매칭한다. 이름이 바뀐 버튼도 여전히 createProject를 생성한다.

도구는 앱이 쓰기를 확인한 경우에만 존재한다

DOM 노드 계산은 페이지의 모든 버튼에 대해 그럴듯해 보이는 도구를 생성한다. apic은 앱 자체가 상태 변경을 주장할 때만 도구를 생성하며, 세 가지 다른 앱 동작을 다루는 세 가지 신호를 통해 확인한다:

동작

예시

신호

알림-후-유지

라벨 생성

상태 영역의 성공 배너

알림-후-이동

프로젝트 생성

URL 변경 후에도 배너가 유지됨

무음-추가

칸반 빠른 추가

제출된 값이 렌더링된 콘텐츠로 나타남

재배치

카드를 열 사이로 드래그

카드의 컨테이너가 변경됨

재배치는 드래그에 배너가 없고 아무것도 반향하지 않기 때문에 중요하다 — 카드는 이미 존재했다. 포함 관계 변경이 증거이며, 어떤 미용적 재렌더링도 이를 생성할 수 없다.

레시피는 위치가 아닌 정체성에 바인딩된다

Vikunja는 페이지를 로드할 때마다 요소 ID를 재생성하므로 저장된 선택자는 도착 즉시 죽은 것이다. 레시피는 필드가 무엇인지 — 라벨, 플레이스홀더, 이름 — 기록하고, 리플레이는 이를 실시간으로 재해석하며, 안정-우선 선택자 체인(name → 안정적 ID → 플레이스홀더 → 생성된 ID 마지막)으로 폴백한다.

결과

UI에서 컴파일됨. 대상의 OpenAPI 사양은 컴파일 중에 절대 읽히지 않는다 — 점수 산정의 기준 진실로만 사용되며, 그래서 리콜 수치가 의미를 갖는 것이다.

숫자 앞에 분모를 명시한다: 18은 Vikunja 자체 OpenAPI 사양에서 /projects, /tasks, /labels의 모든 쓰기 작업(POST/PUT/DELETE)으로, 보드 제스처가 아닌 것 — 팀, 프로젝트 수준 권한, 링크 공유, 첨부 파일, 작업 관계, 복제, 벌크 엔드포인트, 읽음 확인 — 을 제거한 후의 수다. Vikunja는 총 105개의 쓰기 작업을 게시한다; 18은 사람이 칸반 보드에서 수행할 수 있는 하위 집합이며, 각 생성된 도구는 그 중 최대 하나만 주장할 수 있으므로 느슨한 매칭으로 리콜이 부풀려질 수 없다.

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

9개의 도구가 발견되었고, 9개가 제공되었다. 거부된 도구는 삭제되지 않는다 — verified: falsetools.json에 남는다. 거부된 도구는 컴파일러에 대한 증거이지 쓰레기가 아니기 때문이다.

markTask는 불안정하며 그 자체가 9/9보다 더 가치 있다. 동일한 번들에 대한 두 번의 연속 검증 실행, 그 사이 변경 없음, 8/9 후 9/9를 주었다: *"관찰된 변이는 있지만 쓰기를 확인한 것이 없음"*으로 실패한 후 *"성공 — 작업이 성공적으로 저장되었습니다."*로 통과했다. 가능한 원인은 시드된 작업의 상태다 — 이미 완료된 작업에 도달하면 컨트롤이 MARK AS UNDONE으로 읽히고 다르게 확인한다. 매개변수를 받지 않으므로 인수로도 구분할 수 없다.

이는 아래에 미해결로 나열된 플레이크-대-드리프트 문제의 실제 사례다: watch는 그 실패를 드리프트로 계산하여 heal을 호출할 텐데, 실제로는 아무것도 드리프트하지 않았다.

라이브 오후 동안의 지속 검증:

327 checks · 118 breaks · 3 automatic repairs · MTTR 20s

(out/watch-stats.json, 11:33 BST부터 38사이클, 이 글을 쓰는 동안에도 계속 실행 중 — 카운터가 움직인다.)

그 중단 횟수를 있는 그대로 읽어라. stats.breaks++는 모든 사이클의 모든 빨간 리플레이에서 발생하므로, 38사이클 동안 빨간 상태를 유지하는 세 도구는 ~114 중단으로 읽힌다 — 118개의 개별 드리프트 이벤트가 아니라 빨간 도구-사이클 횟수다. 그리고 이 와처는 heal() 수정 전인 11:33에 시작되었는데, heal()replay()의 오프너가 실제로 클릭하는 새로운 provenance 없이 수리된 레시피를 반환했다; 따라서 컨트롤 이름이 바뀐 도구는 매 사이클 치유되었고 어떤 것도 초록이 되지 않았다. 그것이 6/9의 대부분이다. 코드에서 수정되었으며, 비교 가능한 기간 동안 재수집되지 않았다.

파트너 기술

각각 단계가 있으며, 각각 차단보다는 성능 저하로 작동한다: 전체 파이프라인은 API 키 없이도 감소된 충실도로 실행된다. 이 속성 덕분에 자격 증명이 도착하기 전에 컴파일러를 구축할 수 있었고 — 또한 통합이 컴파일이 알아차리지 못한 채 기여를 중단할 수 있는 이유이기도 하며, 상태 열이 기록하는 것이 바로 그것이다.

Tech

Stage

Why it earns its place

Status

OpenAI

Verify

예측된 효과가 실제로 발생했는지에 대한 독립적 판정. 키 없는 diff 기준선 위에 얹혀 있다. 거부를 유지할 수는 있지만, 뒤집을 수는 없다

사용 중verify가 거부한 유일한 도구에 대해 판정을 내렸다

fal

Perceive

의미 있는 변화와 외관상의 변화를 구분하는 빠른 VLM. DOM diff가 모호할 때만 에스컬레이션된다

사용 중 — 마지막 컴파일에서 에스컬레이션된 4/4 단계를 판정했고, 그중 2개는 외관상 변화로 판정. CLI 경로 전용; compile_app은 에스컬레이션하지 않음

Pioneer

Verify, Distil

apic 자체 verify 증거로 파인튜닝된 GLiNER2 인코더가 GPT-4.1-mini 판정기를 대체한다 — 그리고 홀드아웃 도구에서 이를 능가한다(아래 참조). 또한 distill.js의 diff 텍스트 분류기이기도 하다

사용 중PIONEER_JUDGE_MODEL 설정됨: 위의 실시간 verify 패스는 파인튜닝된 인코더가 판정했고, 8/9, 모든 판정이 106–183 ms

h

Explore

페이지를 읽고 키 없는 어휘가 거부한 쓰기 동작의 이름을 밝힌다

사용 중 — 시드당 한 번씩 남은 항목에 대해 실행됨; Vikunja에서 3개 중 0개를 정확히 이름 붙임

Tavily

Ground

앱 문서 → 도메인 어휘. 그래서 도구가 btn_submit_2가 아니라 createIssue로 이름 붙는다

사용 중ground.js가 첫 시드 전에 실행됨; 내장 테이블에 추가되며, 호스트별로 캐시되고, CLI 경로 전용

이중 계층 분할은 제품 자체의 논지를 그 자신에게 적용한 것이다: fal은 저비용 고빈도 지각 계층이고, OpenAI는 고비용 저빈도 추론 계층이다. 실패할 때 에스컬레이션하지, 모든 호출에서 에스컬레이션하지 않는다.

각각이 실제로 어떻게 호출되는가

h — holo3-1-35b-a3b, api.hcompany.ai/v1 (OpenAI 호환). gesture()는 컨트롤의 표시 텍스트를 정규식으로 <verb, resource> 쌍에 매핑하고, 그 외의 모든 것은 null을 반환한다. 그 null이 정밀도 게이트이며 동시에 재현율이 떨어지는 지점이기도 하다: 아이콘 전용 버튼, 동사로 시작하지 않는 컨트롤, 또는 어휘가 예상하지 못한 표현을 쓰는 앱은 아무리 명확하게 쓰여 있어도 버려진다. h는 바로 그 집합을 위한 에스컬레이션 계층이다 — discover.jsclassify()가 페이지의 JPEG와 거부된 컨트롤들을 시드당 한 번 보내고, 그중 어떤 것이 쓰기 동작인지 묻는다.

세 가지가 정밀도 손실을 막는다. 답변은 plan.gestureFrom()이 폐쇄 어휘(동사 6개, 리소스 4개)에 대해 검증하므로, 발명된 동사가 도구 이름이 될 수 없다. 범위 밖 컨트롤은 제안되지 않고 보류된다. ADD TO FAVORITES를 제외하는 것은 범위 결정이지 모델이 메울 구멍이 아니기 때문이다. 그리고 분류된 컨트롤도 다른 모든 후보처럼 앱이 쓰기 동작을 확인하게 해야 한다.

측정 결과, 이 README가 보고하는 컴파일에서: h는 Vikunja의 작업 페이지에서 어휘가 해결하지 못한 세 컨트롤을 읽고 그중 하나의 이름을 밝힌다 — 정규식이 완전히 버리는 아이콘 전용 컨트롤이다:

! h read 3 unresolved controls, named 1
! h: "Kanban bucket: To-Do" -> move task (Pencil icon allows changing task status)

그것이 에스컬레이션 계층이 존재하는 이유를 수행하는 것이다: 선행 동사도 쓸 수 있는 텍스트도 없는 컨트롤이, 아이콘에서 복구되어 폐쇄 어휘로 매핑된다.

도구를 추가하지 않았고, 추가했다고 주장하지도 않는다. move task는 그 시점에 이미 두 번 발견되었다 — 보드 드래그(Move card between columns)와 작업 페이지의 버킷 드롭다운(Kanban bucket: Doing)으로 — 그래서 h의 답변은 드래그가 만들어낸 moveTask로 중복 제거되었다. 이 대상에서 h는 보강이지 재현율이 아니다: 두 경로가 이미 도달한 동작에 대한 세 번째 독립 경로다. 이 파일의 이전 개정판은 h가 도달되지 않았고 아무것도 이름 붙이지 않았다고 했는데, 둘 다 틀렸다.

h가 재현율을 더하는지는 여기서 검증되지 않았다. Vikunja의 쓰기 동작이 비정상적으로 잘 라벨링되어 있기 때문이다. h가 만들어진 경우 — 버튼이 아이콘인 앱 — 는 정확히 이 대상이 제시하지 않는 경우다. 키가 없으면 컴파일은 그 보강을 잃고 그 외에는 아무것도 잃지 않는다.

fal — google/gemini-2.5-flash-lite via fal-ai/any-llm/vision. DOM differ는 페이지가 변경되었는지를 말한다. 텍스트가 설명하지 않는 변경 — 열을 옮긴 카드, 그저 불이 켜진 컨트롤 — 은 판정할 수 없다. perceive.jsadjudicate()가 그런 단계들만, 그리고 오직 그런 단계만 픽셀로 에스컬레이션한다.

측정 결과, 마지막 전체 컴파일에서: vision: 4/4 escalated steps judged by fal, 1 drag corroborated, 2 found cosmetic. 두 개의 외관상 판정이 흥미로운 절반이다 — fal이 쓰기 동작으로 프로브되었을 후보들을 제거한 것이다. cli.js에서 실행되며, MCP 서버의 compile_app을 통한 컴파일은 에스컬레이션하지 않는다.

OpenAI — gpt-4.1-mini, 구조화된 출력. verify.js는 모든 발행된 도구를 앱이 본 적 없는 인자로 콜드 재생하고, 결과를 두 번 판정한다: 먼저 결정적 diff 기준선, 그다음 모델. 모델은 거부를 유지할 수 있고 절대 뒤집지 못한다 — diff가 확인하지 못한 도구는 판정기가 아무리 확신해도 거부된 채로 남는다.

측정 결과: markTask가 실패한 실행에서 그 기록은 openai/gpt-4.1-mini disagreed but cannot overturn a rejection으로 읽힌다. 그 비대칭은 의도적이다: 자신의 추측을 승격시킬 수 있는 판정기는 정밀도 누수다.

Pioneer — GLiNER2 (fastino/gliner2-base-v1), 단계당 POST /inference 1회. distill.js는 각 단계의 diff 텍스트를 자체 요청으로 보내고, 0.6 신뢰도 임계값 이상에서 상태 변경 클래스, 파괴적 플래그, 도메인 명사를 돌려받는다. 예전에는 전체 궤적을 배치로 보냈는데, 배치가 아래 세 번째로 힘들게 얻은 교훈의 주제다: 같은 텍스트가 단독으로는 creation 0.777, 위치 0에서는 creation 1.000, 뒤집힌 배치의 위치 2에서는 DELETION 0.600으로 채점되었다 — 임계값을 통과하는 잘못된 라벨. PIONEER_MODEL의 완료된 학습 작업 ID는 기본 인코더를 apic 자체 라벨로 파인튜닝된 체크포인트로 교체한다 — 시스템이 자신의 지각 계층을 컴파일하는 것 — 그 외에는 아무것도 바뀌지 않는다.

Pioneer — 파인튜닝된 verify 판정기. 이것이 Pioneer 사이드 챌린지 출품작이다: 일반 목적 LLM API 호출을 능가하거나 대체하는 모델을 파인튜닝한다. 대체하는 호출은 verify.jsjudgeModel() — GPT-4.1-mini, 200단어 시스템 프롬프트, 구조화된 출력, 재생된 도구당 한 질문: 이 DOM diff가 주어졌을 때, 예측된 쓰기 동작이 실제로 발생했는가? 그것은 채팅 완성으로 위장한 이중 라벨 텍스트 분류다.

pioneer-train.js는 수동 라벨링 없이 제품 자체의 산출물로 대체품을 만든다:

  1. collect — 컴파일된 모든 도구를 verifyAll()을 통해 새 인자로 여섯 번 재생하고, 증거와 출시된 판정기(diff 기준선 + GPT)가 내린 판정을 기록한다. 실제 54행.

  2. dataset — 기준선이 키로 삼는 증거를 삭제하여(배너 사라짐, 에코가 입력한 입력 필드로 이동, 인자 미충족, 재생 실패, 변경 없음) 음성을 도출하고, 라벨을 보존하는 양성(노드 순서 역전, 무관 노드 추가, 인자를 사람이 입력할 값으로 이름 변경)을 도출한다. 모든 파생 행은 동일한 결정적 기준선으로 재라벨링된다. 788행; 도구별로 홀드아웃되므로 벤치마크는 인코더가 본 적 없는 도구를 측정한다.

  3. upload / trainPOST /felix/datasets/upload/url → 사전 서명된 PUT → POST /felix/training-jobs, fastino/gliner2-base-v1, LoRA, 12 에폭. 약 4분 만에 학습된다.

  4. bench — 홀드아웃 행을 두 판정기 모두에 통과시킨다. LLM은 변경되지 않은 judgeModel()로 호출되므로, 프로덕션에서 보는 것과 정확히 동일하게 본다.

판정기

정확도

정밀도

재현율

오탐

미탐

ms/행

Pioneer GLiNER2 파인튜닝 (작업 91370379…)

94.4%

100%

87.6%

0

12

150

OpenAI GPT-4.1-mini

89.3%

84.3%

93.8%

17

6

890

215개의 홀드아웃 행, 학습에 없는 두 도구(createTask, assignLabel). 인코더는 제로 오탐을 위해 일부 재현율을 포기한다 — 이 판정기에 맞는 트레이드오프다. 설계상 거부를 유지할 수는 있어도 추측을 승격할 수는 없다. PIONEER_JUDGE_MODEL을 작업 ID로 설정하면 verify가 그것을 사용한다; OpenAI는 폴백으로 대기 상태를 유지하고, 키가 전혀 없어도 기준선은 여전히 실행된다.

힘들게 배운 세 가지, 모두 실시간으로 검증되고 코드에 기록됨: 분류 사양 내의 multi_label/top_k는 통합 /inference 경로가 모든 텍스트에 대해 categories: []를 반환하게 한다(이것이, 크레딧이 아니라, distil 단계가 아침 내내 조용했던 이유다); GLiNER2는 LoRA로만 학습된다 — training_type: "full"은 수락되고 Modal 내부에서 로그 줄 없이 실패한다; 그리고 파인튜닝된 모델의 배치 추론(text: [...])은 입력과 정렬되지 않는 라벨을 반환하므로, 판정기는 요청당 하나의 텍스트를 보낸다.

Tavily — api.tavily.com/search, 결과 5개, 답변 포함. ground.js는 첫 시드 전에 실행된다. plan.js는 Vikunja의 명사 — bucket, task, label, project — 를 제공하며, 그 외의 것을 가리키면 gesture()는 이슈와 리포지토리를 들어본 적 없는 테이블에 의해 질문받고, null을 반환하며, 컨트롤은 버려진다. Tavily는 대상의 자체 문서를 가져온다; OpenAI는 그 산문을 엄격한 스키마 아래 폐쇄 명사 집합으로 구조화한다; 모든 용어는 /^[a-z][a-z-]{1,18}$/에 대해 검증되고, 12개로 제한되며, 내장 테이블을 대체하지 않고 병합되므로, 그라운딩은 어휘를 추가할 수 있고 Vikunja의 어휘를 빼앗을 수는 없다. .apic/ 아래 호스트별로 캐시되므로, 반복 컴파일은 비용이 들지 않고 데모는 장소 와이파이에 의존하지 않는다.

세 단계로 저하된다 — Tavily 키 없음, 증거 없음; OpenAI 키 없음, 증거를 구조화할 수 없음; 검증을 통과하는 것 없음 — 각 단계는 로그를 남기고 내장 테이블을 그대로 둔다. fal처럼 cli.js에서 실행된다: MCP 서버의 compile_app은 내장 어휘를 사용한다.

그래서 위의 재현율 수치는 키 없이 생산되었다, 에스컬레이션된 지각 단계에 fal, verify 패스에 OpenAI 판정기를 사용했다. 그것은 전체 파트너 스택의 시연이 아니며, 이 README는 그렇게 가장하지 않을 것이다.

설정

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

대상 앱(자체 호스팅, 일회용 — 절대 제3자 제품을 가리키지 말 것):

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

명령어

기능

npm run doctor

어떤 자격 증명이 작동하는지, 어떤 대상이 가동 중인지 확인

npm run compile

탐색 → 합성 → 생성

npm run verify

모든 도구를 차갑게 재실행; 생존자만 서빙됨

npm run watch

자동 복구로 지속 검증

npm run score

실제 API에 대한 재현율과 정밀도 측정

모든 명령어는 동일한 두 변수를 읽으므로, 전체 실행을 라이브 번들 대신 대체 번들로 지정할 수 있습니다:

APIC_OUT_DIR=out/rescue APIC_APP=vikunja npm run verify

변수

기본값

의미

APIC_OUT_DIR

generated

컴파일된 번들이 저장되는 위치. APIC_GENERATED도 별칭으로 허용됨

APIC_APP

vikunja

그 안에서 사용할 번들

TARGET_URL

http://localhost:3456

컴파일 대상 앱

TARGET_USER / TARGET_PASS

apic / —

대상에 대한 자격 증명

TARGET_LOGIN_PATH

자동 감지

로그인 양식이 /login 스타일 경로에 없을 때만 필요

APIC_SEEDS

/projects,/labels

탐색을 시작할 페이지

시드와 대상은 환경 변수로 주입됩니다 — 컴파일러는 Vikunja의 경로를 알지 못합니다:

APIC_APP=gitea TARGET_URL=http://localhost:3001 APIC_SEEDS=/repo/create,/issues npm run compile

생성된 출력물

generated/vikunja/ — 서버, 스키마, 그리고 각 도구에 대한 근거 자료. 그 디렉터리의 어떤 것도 사람이 작성한 것이 아닙니다.

MCP 서버로 사용하기

claude mcp add apic -- node /path/to/apic/src/server.js

src/server.js하나의 도구, compile_app으로 시작합니다. URL을 지정하면 파이프라인을 인프로세스로 실행하고, generated/<app>/에 출력하며, 컴파일된 도구들을 자체적으로 등록하고, notifications/tools/list_changed를 전송합니다 — 따라서 동일한 연결에서 재시작 없이 호출 가능합니다. 콜드 스타트에서:

[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"}

재시작이 필요한 컴파일러는 빌드 단계입니다. 재시작이 필요 없는 것은 라이브 컴파일러입니다. 클라이언트 호환성 노트와 전체 트랜스크립트: docs/mcp-client.md.

두 막다른 길은 보고되지 않고, 답변됩니다

클라이언트는 무언가 누락된 순간에만 apic을 만납니다. 그리고 그런 순간들은 모두 대화를 종료시키곤 했습니다.

존재하지 않는 도구는 그것을 생성할 컴파일을 반환합니다:

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" }

앱이 그 아래에서 이동해버린 도구는 호출 경로에서 복구됩니다 — watch는 타이머로 치유하고, 서버는 요청 시 치유하며, 동일한 heal()을 통해. 도구가 빨간불이 되면, 컴파일러는 그 단일 액션을 재탐색하고, 호출자가 실패를 보기 전에 복구가 tools.json에 기록됩니다:

[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 } }

건강한 도구는 이 모든 것의 영향을 받지 않습니다: 동일한 호출, 4.4초, 재탐색 없음.

관련 작업 및 차이점

프로젝트

기능

차이점

Playwright MCP

브라우저 자동화를 타입화된 MCP 도구로 제공

일반 동사(click(ref)) vs 앱 특화 명사(createTask(title)). 런타임 vs 컴파일 타임

Apify MCP Server

Actor 입력 스키마에서 타입화된 도구를 자동 생성

Actor는 사람이 작성 — apic은 사람이 작성한 계약에서 래퍼를 생성합니다

Apify AI Web Scraper

URL + 자연어 → 구조화된 데이터

데이터를 반환할 뿐, 인터페이스는 아님 — 그리고 매 호출마다 LLM을 재실행합니다

cli-printing-press

URL/HAR/OpenAPI → CLI + MCP 서버, 검증 게이트 포함

네트워크 트래픽을 스니핑 — 앱에 이미 API가 있어야 합니다. apic은 UI를 구동합니다

Easy MCP

OpenAPI 스pec → MCP 도구

API가 이미 존재해야 합니다

Alita

에이전트가 작업당 MCP를 생성하고 재사용

도구를 웹 검색으로 생성 — apic은 소프트웨어를 조작하여 도출합니다

WebMCP

페이지가 JavaScript로 자체 도구를 선언

앱 개발자가 채택해야 합니다

Voyager

스킬을 작성, 검증, 저장, 재사용

검증-후-유지 루프의 선조

루프는 새롭지 않습니다 — 능력이 어디서 오는지가 다릅니다. Alita는 인터넷을 읽어 도구를 만들고; cli-printing-press는 네트워크를 읽고; Easy MCP는 스펙을 읽습니다. apic은 앱을 읽습니다.

아직 작동하지 않는 것

솔직히 말하면, 실패 모드를 숨기지 않는 컴파일러는 아닙니다.

  • h는 14개의 후보 중 0개를 이름 지었습니다. 그것은 어휘가 거부한 컨트롤을 읽습니다 — 그리고 그 거부는 정확했습니다: Vikunja의 보드 슬라이스는 이미 정규식으로 덮여 있습니다. 확대는 실측된 것이 아니라 측정된 것입니다; 이득은 여기서 0이고, 컨트롤이 동사구가 아닌 아이콘인 대상이 그것을 보여줄 사례입니다.

  • compile_app은 축소된 파이프라인을 실행합니다. compile.js는 MCP 서버가 호출하는 인프로세스 컴파일이며, cli.js에서 다섯 가지를 뺀 것입니다: 접지(Tavily/OpenAI), 시드 탐색, 전용 양식 페이지 프로브, 작업 세부 정보 시드, Kanban 드래그 — 그리고 fal 비전 계층 — adjudicate()cli.js에서만 실행됩니다. 위 트랜스크립트가 npm run compile이 9개를 생성하는 곳에서 4개의 도구를 보여주는 이유입니다: 라이브 컴파일러 데모와 9-도구 번들은 서로 다른 두 경로입니다, 그리고 CLI만 회상 수치가 설명하는 것입니다.

  • Pioneer는 오전 내내 사용 불가로 보였습니다 — 먼저 403 payment_method_required, 그리고 새 키 후에는 categories: []가 모든 호출에서 발생했습니다. 이는 API가 아니라 요청 형태 버그였습니다(multi_label/top_k). 각 통합은 조용히 저하되도록 작성되었고, 실제로 저하되었습니다 — 저하 자체가 의도된 동작입니다; 오전 내내 알아차리지 못한 것이 문제입니다.

  • 파인튜닝된 판별자는 하나의 앱을 보았습니다. 788개의 훈련 행은 모두 Vikunja입니다. 보류된 분할은 도구별이 아니라 앱별입니다; Gitea 또는 ParaBank 벤치 가 다음 정직한 테스트이며, collect를 두 번째 대상에 대해 실행하는 것이 그것을 얻는 방법입니다.

  • 두 번째 대상은 끝까지 컴파일됩니다. Gitea는 이제 엔드 투 엔드로 컴파일됩니다 — createRepositorycreateIssue, 둘 다 검증됨, swagger.v1.json에 대한 13개 중 2개 슬라이스. 탐색에는 변경이 필요 없었습니다: 두 가지 수정은 확인 클래스였습니다(Gitea는 제출된 값을 담은 새 URL에서 결과를 서빙함으로써 쓰기를 확인하며, 게이트는 배너와 본문 에코만 찾았습니다) 그리고 컨테이너/항목 URL 패턴을 cli.js에서 APIC_SEEDS가 이미 있던 구성으로 이동한 것입니다. 라벨 및 댓글 액션은 여전히 누락됩니다: 그것들은 어휘가 이름을 지정하지 않는 컨트롤 뒤에 있으며, h는 받은 14개 중 어떤 것도 이름을 지정하지 못했습니다.

  • Vikunja에서 18개 중 8개 회상. 누락: 버킷 생성, 댓글, 관계 및 첨부 파일.

  • markTask는 대략 두 번 실행 중 한 번 실패합니다 (결과 참조). 그 효과는 실제이며 관찰됩니다; 그것을 확인하는 것이 무엇이든 작업의 기존 상태에 달려 있습니다. 라이브 npm run verify는 8/9 또는 9/9를 출력할 것으로 예상해야 합니다.

  • 동시 실행이 충돌합니다. 모든 명령어는 .apic/session.json에 하나의 저장된 세션을 공유하므로, 동시에 시작된 컴파일과 검증은 실행 중에 서로의 브라우저 컨텍스트를 파괴할 수 있습니다(Error setting storage state: Execution context was destroyed). 실행마다 고유한 APIC_SESSION을 전달하여 해결하십시오; 실제 수정은 기본적으로 실행별 세션 파일입니다.

  • Watch는 모든 실패를 드리프트로 취급합니다. 실제 플레이크-대-드리프트 분류는 존재하지 않습니다. 세 가지 오탐 클래스가 수동으로 수정되었습니다 — 속도 제한, 토큰 만료, 그리고 충돌한 페이지 — 하지만 일반적인 문제는 남아 있습니다.

  • 의미론적 변경은 감지되지 않으며 위험합니다. deleteProject가 삭제 대신 보관을 시작한다면, 선택기를 치유하는 것은 잘못된 답입니다. 검증은 효과가 발생했는지 확인할 뿐, 동일한 효과인지는 확인하지 않습니다.

  • 역방향 액션이 없어서, 스위트는 자체 픽스처를 오염시킵니다. 반복된 실행은 대상이 리셋될 때까지 저하시킵니다.

  • 인증은 우회됩니다. 로그인 한 번, 사용자 한 명, 권한 범위 없음 — 이것이 실제 엔터프라이즈 소프트웨어에서 문제의 어려운 부분입니다.

사전 작업 선언

해커톤에서 처음부터 작성되었습니다. 가져온 보일러플레이트 없음; 저장소는 이벤트 당일 아침에 비어 있는 상태로 생성되었습니다. Playwright, MCP SDK, 그리고 OpenAI 및 fal 클라이언트가 유일한 의존성입니다.

라이선스

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