대시보드
Morit Plugin7. SDK, MCP, API

수명주기와 HTTP API

모든 사용자 API는 Morit bearer session과 사용자 소유권 검사를 요구합니다. 앱은 repository 계층을 통해 호출하고 UI에서 URL을 직접 조합하지 않습니다.

설치 수명주기

text
package 수신
  → 크기·ZIP 경로·entry 검사
  → manifest·fragment compiled 결과 검사
  → Ed25519 signature와 publisher 확인
  → dependency bundle 확인
  → 임시 package 저장
  → Installation + default Instance + child dependency를 한 transaction으로 기록
  → package를 content-addressed store에 확정
  → catalog 새로고침

중간 단계가 실패하면 임시 파일과 DB 변경을 함께 rollback합니다. 목록 조회 실패를 설치 성공으로 바꾸거나, 부분 Installation이 남은 상태에서 duplicate 오류를 반환하지 않습니다.

한 Installation에는 설치와 함께 유지되는 default Instance가 있습니다. 여러 외부 계정은 이 Instance의 여러 Connection으로 관리합니다. 앱이 같은 package의 root Instance를 복제하지 않으며 dependency Child Instance는 Host가 내부에서 생성·정리합니다.

Marketplace와 설치

methodpath목적
GET/v1/plugin-marketplace공개 Deployment 목록·검색
GET/v1/plugin-marketplace/{deployment_id}상세 metadata
GET/v1/plugin-marketplace/{deployment_id}/icon검증된 icon
POST/v1/plugin-marketplace/{deployment_id}/installexact Deployment artifact 설치
POST/v1/plugins/installraw signed .mplg 설치
POST/v1/plugins/create제한된 앱 Builder package 생성·설치

Raw install content type은 application/vnd.morit.plugin+zip, 최대 2 MiB입니다. Marketplace install과 파일 install은 같은 Host 설치 경로와 rollback 정책을 사용합니다.

조회와 설정

methodpath목적
GET/v1/plugins기존 호환용 설치 목록
GET/v1/plugin-installationsInstallation 목록
GET/v1/plugin-instancesdefault/child Instance 목록
GET/v1/plugin-instances/{instance_id}Instance 상태·Connection·dependency
PATCH/v1/plugin-instances/{instance_id}이름, enabled, permission, settings 변경
DELETE/v1/plugin-instances/{instance_id}/storage해당 Instance의 Local Storage 초기화
DELETE/v1/plugin-instances/{instance_id}Instance와 descendant 정리용 API
GET/v1/plugins/{plugin_id}plugin ID 기준 설치 상세
PATCH/v1/plugins/{plugin_id}호환용 default 설치 설정

새 앱 흐름은 Installation 목록과 default Instance를 사용합니다. enabled, compatibility, granted permission, required Connection, dependency가 모두 준비되어야 state가 active가 됩니다. 설정 변경은 generation을 갱신해 오래된 실행 결과가 새 상태를 덮지 못하게 합니다.

Connection과 OAuth

methodpath목적
POST/v1/plugin-instances/{instance_id}/connectionsCredential Connection 생성
PATCH/v1/plugin-instances/{instance_id}/connections/{connection_id}label·default 선택 변경
POST/v1/plugin-instances/{instance_id}/connections/{connection_id}/oauth/startInstance OAuth 시작
DELETE/v1/plugin-instances/{instance_id}/connections/{connection_id}Connection 해제
PUT/v1/plugins/{plugin_id}/credentials/{credential_id}legacy/default API token 설정
POST/v1/plugins/{plugin_id}/credentials/{credential_id}/oauth/startlegacy/default OAuth 시작
GET/v1/plugins/oauth/callback/{provider_id}provider callback
DELETE/v1/plugins/{plugin_id}/credentials/{credential_id}legacy/default credential 삭제

allow_multiple: true인 Credential은 Connection을 여러 개 만들 수 있습니다. OAuth callback은 state와 code를 확인한 뒤 Connection을 갱신하며 token을 URL·로그·응답에 반환하지 않습니다.

Capability 실행

methodpath목적
POST/v1/plugin-instances/{instance_id}/capabilities/{capability}/execute특정 Instance 실행
POST/v1/plugins/{plugin_id}/capabilities/{capability}/executedefault Instance 호환 실행
POST/v1/plugins/searchenabled Search Provider 통합 검색
POST/v1/plugins/background/rundue background 실행

실행 응답:

json
{
  "plugin_id": "com.example.study",
  "instance_id": "00000000-0000-4000-8000-000000000000",
  "capability": "com.example.study.today",
  "state": "completed",
  "summary": "오늘 일정은 3개입니다.",
  "data": {},
  "evidence": [],
  "error_message": null,
  "error_code": null,
  "retryable": false
}

Host는 실행 직전에 actor, owner, enabled, compatible version, generation, permission, Connection, dependency, timeout을 다시 확인합니다. 실패는 error_coderetryable을 구분하며 성공 summary로 숨기지 않습니다.

Host action outbox

methodpath목적
GET/v1/plugins/host-actions최대 100개의 pending action lease
POST/v1/plugins/host-actions/{event_id}/result플랫폼 적용 성공·실패 ACK

앱은 action을 적용한 뒤 반드시 result를 전송합니다. lease 만료 시 중복 전달될 수 있으므로 notification key와 storage action은 idempotent하게 처리합니다.

Package, UI 이미지와 삭제

methodpath목적
GET/v1/plugins/{plugin_id}/package설치된 exact .mplg attachment 다운로드
GET/v1/plugins/{plugin_id}/assets/{asset_path:path}검증된 package asset 읽기
POST/v1/plugin-instances/{instance_id}/ui-images:fetchcapability 결과의 원격 이미지 Host proxy
DELETE/v1/plugins/{plugin_id}Installation, Instance, Connection 삭제

package 응답은 attachment Content-Disposition을 사용합니다. 삭제 시 purge_data와 manifest data_policy를 적용하되 credential, OAuth state, pending Host action은 항상 별도 보안 정리를 거칩니다.

Storage 초기화는 actor가 소유한 정확한 Instance만 대상으로 하며 같은 Installation의 다른 Instance와 다른 사용자 데이터는 건드리지 않습니다. data_policy: retain은 uninstall/reinstall에만 적용되고 사용자가 명시적으로 초기화하면 즉시 삭제됩니다. 자세한 수명주기는 Plugin Local Storage와 AI 접근을 참고하세요.

Asset API는 활성화된 사용자 소유 설치가 UI Runtime v2에서 실제 참조한 이미지에만 접근할 수 있습니다. Host는 저장 package의 hash·signature·manifest를 다시 확인하고 확장자와 PNG/JPEG/GIF/WebP magic byte, 실제 이미지 포맷을 검사합니다. package asset과 원격 이미지에 공통으로 가로·세로 각각 4096 px, 애니메이션 128 frame, width × height × frame 수 기준 frame 합산 16,000,000 pixel 한도를 적용합니다. 응답은 private cache, ETag, nosniff, same-origin resource policy를 사용하며 traversal·미참조 asset·다른 사용자의 설치는 노출하지 않습니다.

원격 이미지 API는 앱의 Host renderer가 호출하는 인증된 binary endpoint입니다. JSON body는 {"url":"https://..."}이고, URL은 image 또는 avatar의 capability 결과 binding에서 해석한 값이어야 합니다. 앱과 플러그인은 외부 URL을 직접 fetch하지 않습니다. 요청 actor가 Instance owner여야 하고, package Manifest의 network 요청과 해당 활성 Instance의 network grant가 모두 유효해야 합니다.

Host는 공개 HTTPS만 허용하고 DNS/IP SSRF 검사를 거치며 redirect를 따르지 않습니다. upstream 응답은 PNG/JPEG/GIF/WebP MIME type, magic byte, 실제 이미지 포맷이 일치해야 합니다. 본문은 최대 512 KiB이고 위의 공통 dimension·animation 한도를 적용합니다. 성공 응답은 private, no-store, Vary: Authorization, nosniff, same-origin resource policy를 사용합니다. 권한 부족은 403, 비활성화·generation/grant 변경은 409, unsafe URL·redirect는 422, 크기 초과는 413, 지원하지 않거나 손상된 이미지는 415, upstream 실패는 502, Host network 경계 미설정은 503으로 구분합니다. 소유하지 않은 Instance는 상세 정보를 노출하지 않습니다.

AI 생성/분석 artifact는 별도 소유권 경계인 GET /v1/ai/conversations/{conversation_id}/code-executions/{execution_id}/artifacts/{attachment_id}/access 에서만 signed URL을 발급합니다. 완료된 python_code, image_generation, image_edit 실행의 저장된 artifact manifest와 attachment 행이 모두 일치해야 하며 다른 대화·실행의 attachment ID는 404입니다.

앱 시작 복구

시작할 때 DB Installation과 content-addressed package store를 함께 점검합니다.

  • DB가 없는 고아 임시/package 파일 정리
  • DB가 가리키는 package가 없거나 hash가 다르면 명확한 load error
  • 오래된 partial Connection/OAuth state 만료
  • dependency Child Instance 재조정
  • pending Host action lease 회수

손상된 metadata를 빈 목록으로 바꾸지 않습니다. 목록 없음, 인증 실패, 저장소 손상, network 실패를 각각 구분해 사용자에게 재시도 또는 복구 동작을 제공합니다.