대시보드
Morit Plugin2. 프로젝트와 계약

Manifest 레퍼런스

manifest.json은 UTF-8 JSON 객체입니다. Host는 schema 1과 2를 읽으며 새 프로젝트는 schema 2를 사용합니다. 알 수 없는 필드는 무시하지 않고 오류로 처리합니다.

전체 형태

json
{
  "schema_version": 2,
  "id": "com.example.notes",
  "name": "Notes",
  "icon": "assets/icon.png",
  "short_description": "연결된 노트를 검색합니다.",
  "description": "내 노트 계정을 연결해 검색하고 요약합니다.",
  "category": "productivity",
  "keywords": ["notes", "search"],
  "developer": {"name": "Example", "url": "https://example.com"},
  "homepage_url": "https://example.com/notes",
  "privacy_policy_url": "https://example.com/privacy",
  "publisher": "example",
  "version": "1.0.0",
  "min_morit_version": "1.7.12",
  "max_morit_version": "1.999.999",
  "permissions": ["network", "credentials"],
  "capabilities": [
    {
      "id": "com.example.notes.echo",
      "kind": "tool",
      "title": "입력 확인",
      "description": "입력한 검색어를 확인합니다.",
      "permissions": [],
      "runtime": {"adapter": "text_template", "template": "검색어: {query}"}
    }
  ],
  "ui_extensions": [],
  "credentials": [],
  "slash_commands": [],
  "connectors": [],
  "dependencies": [],
  "required_secrets": [],
  "data_policy": "purge"
}

icon을 선언했다면 assets/icon.png 파일도 실제 프로젝트에 있어야 합니다. 준비 전에는 필드를 생략하고 존재하지 않는 asset 경로를 넣지 않습니다.

신원과 표시 정보

필드규칙
id소문자 reverse-domain ID, 예: com.example.notes
name1~80자
publisher2~120자의 영문·숫자·점·밑줄·하이픈
versionsemantic version
min_morit_version, max_morit_versionsemantic version, 둘 다 필수
icon패키지의 PNG/JPEG/WebP assets/ 경로
short_description최대 160자
description최대 4,000자
category소문자로 시작하는 2~40자 ID
keywords최대 12개의 고유한 1~40자 문자열
URL 필드사용자 정보가 없는 공개 HTTPS URL

cloud_project_id는 Cloud 기능을 쓸 때 Developer Project가 채우는 UUID입니다. 프로젝트 source에 직접 추측해 넣지 않습니다. required_secrets 또는 cloud_connection_id를 사용하는 Connector가 있으면 이 값이 필요합니다.

권한과 데이터 정책

Manifest permissions는 플러그인이 요청할 수 있는 최대 범위입니다. 각 capability와 UI extension은 그중 자신에게 필요한 일부만 다시 선언합니다.

data_policy는 삭제 시 플러그인 storage 처리 방식을 정합니다.

  • purge: 설치와 함께 저장한 플러그인 데이터를 삭제
  • retain: 재설치를 위해 일반 storage를 유지

credential, OAuth state, pending notification은 두 정책과 무관하게 보안 수명주기에 따라 정리됩니다.

Local Storage

새 저장소는 schema 2에서 명시적으로 선언합니다.

json
{
  "permissions": ["storage", "ai_storage"],
  "storage": {
    "version": 1,
    "namespaces": [
      {"id": "default", "max_bytes": 131072, "ai_access": "read"},
      {"id": "tasks", "max_bytes": 262144, "ai_access": "read_write"}
    ],
    "migrations": []
  }
}

ai_accessread 또는 read_write인 namespace가 있으면 ai_storage 권한이 필수입니다. namespace, quota, migration과 표준 CRUD Tool은 Plugin Local Storage와 AI 접근을 참고하세요.

Capability

json
{
  "id": "com.example.notes.search",
  "kind": "tool",
  "title": "노트 검색",
  "description": "연결한 계정의 노트를 검색합니다.",
  "permissions": ["network", "credentials"],
  "timeout_seconds": 10,
  "input_schema": {
    "type": "object",
    "properties": {"query": {"type": "string", "minLength": 1}},
    "required": ["query"]
  },
  "output_schema": {
    "type": "object",
    "properties": {"items": {"type": "array", "items": {"type": "object"}}},
    "required": ["items"]
  },
  "runtime": {
    "adapter": "http_json",
    "connector_id": "notes_api"
  }
}

kindtool, skill, provider, background, notification 중 하나입니다. 최대 64개이며 timeout은 0.1~30초입니다. capability 권한은 Manifest 권한의 부분집합이어야 합니다. toolskill은 실행 가능한 runtime adapter가 필수입니다. Search providerruntime.role: "search"와 adapter가 필요합니다. input_schema/output_schema는 선택이지만 선언하면 AI Tool·UI·Host가 모두 같은 안전한 JSON Schema 부분집합으로 입력과 결과를 검증합니다. UI binding 정적 검사는 UI Runtime v2를 참고하세요.

UI extension

json
{
  "id": "com.example.notes.screen",
  "point": "screen",
  "title": "내 노트",
  "order": 10,
  "permissions": ["network", "credentials"],
  "config": {
    "ui_schema": 2,
    "view": {"type": "text", "props": {"text": "노트를 검색하세요."}}
  }
}

최대 64개입니다. pointscreen, surface, menu, action, card, settings, workspace, response 중 하나입니다. 상세 선택 기준은 UI extension point, config 계약은 UI Runtime v2를 참고하세요.

point: "response"ui_schema: 2와 A2UI v0.9 metadata/schema가 필수이며 이전 Response UI 형식은 허용하지 않습니다. Host가 활성 Instance, 권한, data source와 schema를 확인한 뒤 catalog에 동적 등록합니다. AI는 등록된 컴포넌트 ID만 선택할 수 있고 결과 데이터는 Host가 주입합니다.

Credential과 Connector

Credential은 사용자별 비밀 값의 종류를 선언합니다.

json
{
  "id": "notes_account",
  "label": "Notes 계정",
  "description": "노트를 읽는 OAuth 연결",
  "kind": "oauth_access_token",
  "required": true,
  "oauth_provider": "notion",
  "allow_multiple": true
}

kindapi_token 또는 oauth_access_token입니다. credential이 하나라도 있으면 Manifest에 credentials 권한이 필요합니다. allow_multiple의 기본값은 true이며 Instance마다 연결을 따로 관리합니다.

Connector는 endpoint, credential, timeout, retry, rate limit을 capability에서 분리합니다.

json
{
  "id": "notes_api",
  "kind": "oauth",
  "label": "Notes API",
  "description": "공식 API 연결",
  "credential_id": "notes_account",
  "cloud_connection_id": "notion",
  "timeout_seconds": 10,
  "retry": {"max_attempts": 3},
  "rate_limit": {"requests": 60, "period_seconds": 60}
}

kindhttps, oauth, api_key, mcp입니다. 공개 endpoint를 직접 지정할 때는 HTTPS만 허용합니다. timeout은 0.130초, retry는 14회, rate-limit 기간은 1~3,600초입니다. OAuth는 credential이 필수이고 API key는 사용자 credential이나 선언된 Cloud secret 중 하나가 필요합니다.

Cloud Secret을 쓰려면 먼저 required_secrets에 대문자 환경 ID를 선언합니다.

json
{
  "id": "EXAMPLE_API_KEY",
  "label": "Example API key",
  "description": "서버 간 요청에 사용합니다.",
  "required": true
}

Dependency와 child package

json
{
  "id": "notes",
  "plugin_id": "com.example.notes_core",
  "required": true,
  "min_version": "1.0.0",
  "max_version": "1.999.999",
  "package_path": "children/notes-core.mplg",
  "exposed_capabilities": ["com.example.notes_core.search"]
}

package_path가 있으면 정확히 대응하는 signed child .mplg가 패키지에 있어야 합니다. 부모는 child_plugin adapter와 exposed_capabilities에 적힌 capability만 호출할 수 있습니다. 부모와 자식은 Instance, settings, credential, storage를 공유하지 않습니다.

Slash Command

json
{
  "id": "com.example.notes.command",
  "command": "notes",
  "title": "노트 검색",
  "description": "연결한 노트를 검색합니다.",
  "capability": "com.example.notes.search",
  "argument_template": {"limit": 10}
}

최대 32개입니다. command/ 없이 소문자·숫자로 시작하는 1~32자이며 _, -를 사용할 수 있습니다. 대상은 같은 플러그인의 tool 또는 skill이어야 합니다.

다음은 Instance와 Connector 모델입니다.