@yoonion/mimi-seed-mcp
Mimi Seed MCP server — Firebase + AdMob + Google Play + App Store management for Claude Code / Codex / Cursor / any MCP client.
npm · fingerprint 3f90cc49c8f50926545fdf8e · repository · RSS
What changed
Changed between 4 September 2026 and 5 October 2026 (first seen 2026-10-05 14:22 UTC)
44 descriptions rewritten, 185 schema or annotation changes with the description left byte-identical, 18 tools added, 2 tools removed.
--- pinned/admob_create_ad_unit +++ observed/admob_create_ad_unit { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "AdMob: Create ad unit" + }, "description": "AdMob 광고 단위 생성 (v1beta — Limited Access)", "execution": { "taskSupport": "forbidden" - "name": "admob_create_ad_unit" + "name": "admob_create_ad_unit", + "title": "AdMob: Create ad unit" }
--- pinned/admob_create_app +++ observed/admob_create_app { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "AdMob: Create app" + }, "description": "AdMob에 새 앱 등록 (v1beta — Limited Access). appStoreId 를 주면 스토어 게시 앱과 링크(Android=패키지명, iOS=App Store 숫자 ID), 없으면 manual(unlinked) 앱.", "execution": { "taskSupport": "forbidden" - "name": "admob_create_app" + "name": "admob_create_app", + "title": "AdMob: Create app" }
--- pinned/admob_get_report +++ observed/admob_get_report { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "AdMob: Get report" + }, "description": "AdMob 수익 리포트 (기간 지정)", "execution": { "taskSupport": "forbidden" - "name": "admob_get_report" + "name": "admob_get_report", + "title": "AdMob: Get report" }
--- pinned/admob_get_today_earnings +++ observed/admob_get_today_earnings { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "AdMob: Get today earnings" + }, "description": "오늘 AdMob 수익 요약", "execution": { "taskSupport": "forbidden" - "name": "admob_get_today_earnings" + "name": "admob_get_today_earnings", + "title": "AdMob: Get today earnings" }
--- pinned/admob_list_accounts +++ observed/admob_list_accounts { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "AdMob: List accounts" + }, "description": "AdMob 계정 목록 조회", "execution": { "taskSupport": "forbidden" - "name": "admob_list_accounts" + "name": "admob_list_accounts", + "title": "AdMob: List accounts" }
--- pinned/admob_list_ad_units +++ observed/admob_list_ad_units { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "AdMob: List ad units" + }, "description": "AdMob 광고 단위 목록", "execution": { "taskSupport": "forbidden" - "name": "admob_list_ad_units" + "name": "admob_list_ad_units", + "title": "AdMob: List ad units" }
--- pinned/admob_list_apps +++ observed/admob_list_apps { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "AdMob: List apps" + }, "description": "AdMob에 등록된 앱 목록", "execution": { "taskSupport": "forbidden" - "name": "admob_list_apps" + "name": "admob_list_apps", + "title": "AdMob: List apps" }
+ tool added: android_check_billing_compliance
--- pinned/android_generate_keystore +++ observed/android_generate_keystore { - "description": "새 Android upload keystore (.jks)를 자동 생성합니다. Java JDK의 keytool이 설치돼 있어야 합니다. 생성 후 반환된 keystoreBase64 / storePassword / keyAlias / keyPassword를 jenkins_upload_keystore 와 jenkins_create_credential 로 Jenkins에 등록하세요. 비밀번호는 이 응답에서만 확인 가능하니 반드시 Jenkins에 즉시 등록하세요.", + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": false, + "readOnlyHint": false, + "title": "Android: Generate keystore" + }, + "description": "새 Android upload keystore (.jks)를 자동 생성합니다. Java JDK의 keytool이 설치돼 있어야 합니다. keystore 와 비밀번호는 ~/.mimi-seed/keystores/<앱>-<시각>/ 에 0600 파일로 저장되고 응답에는 경로만 나옵니다. 그 경로를 jenkins_upload_keystore(keystore_path) 와 jenkins_create_credential(secret_file, secret_field) 에 넘겨 Jenkins에 등록하세요.", "execution": { "taskSupport": "forbidden" }, - "name": "android_generate_keystore" + "name": "android_generate_keystore", + "title": "Android: Generate keystore" }
--- pinned/android_signing_setup +++ observed/android_signing_setup { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Android: Signing setup" + }, "description": "⭐ Android 앱 서명/빌드 설정을 시작할 때 가장 먼저 호출하세요. Play Console 업로드 이력을 확인해 신규 앱인지 기존 앱인지 판별하고, Jenkins credential 등록과 Play Store SA 연결까지 단계별 액션 플랜을 반환합니다. \"Jenkins에 keystore 등록해줘\", \"Android 빌드 설정 해줘\", \"서명 키 설정\" 요청 시 이 도구를 먼저 호출하세요.", "execution": { "taskSupport": "forbidden" + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" }, "project_id": { - "name": "android_signing_setup" + "name": "android_signing_setup", + "title": "Android: Signing setup" }
--- pinned/appstore_add_beta_testers +++ observed/appstore_add_beta_testers { + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Add beta testers" + }, "description": "베타 그룹에 테스터를 초대한다 — POST /v1/betaTesters. 이메일별로 개별 호출하며, 이미 등록된 주소는 실패로 표시하고 나머지는 계속 진행한다. ⚠️ 초대 메일이 즉시 발송된다 — 주소를 사용자에게 확인받고 실행할 것. confirm 필요.", "execution": { "taskSupport": "forbidden" - "name": "appstore_add_beta_testers" + "name": "appstore_add_beta_testers", + "title": "App Store: Add beta testers" }
--- pinned/appstore_add_product_to_review +++ observed/appstore_add_product_to_review { - "description": "App Store IAP/구독 상품을 **단독으로** 심사에 제출한다 — consumable/non_consumable 은 POST /v1/inAppPurchaseSubmissions, subscription 은 POST /v1/subscriptionSubmissions. ⚠️ 호출 즉시 제출된다 (\"묶음에 담기\"가 아니다 — 그런 공개 API 는 존재하지 않는다. reviewSubmissionItems 는 appStoreVersion 계열 관계만 받는다, 2026-07 실측). 이미 승인된 적 있는 상품의 변경분 제출용. **앱 첫 심사** 상품은 Apple 이 \"no pending version\" 409 로 거부한다 — 그 경우 ASC 웹 버전 페이지의 \"앱 내 구입 및 구독\" 섹션에서 담아 버전과 함께 제출해야 한다 (도구가 에러에 안내 첨부). 상품 상태가 READY_TO_SUBMIT 이어야 한다 (MISSING_METADATA 면 appstore_update_product_localization 먼저).", + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Add product to review" + }, + "description": "App Store IAP/구독 상품을 **단독으로** 심사에 제출한다 — consumable/non_consumable 은 POST /v1/inAppPurchaseSubmissions, subscription 은 POST /v1/subscriptionSubmissions. ⚠️ 호출 즉시 제출된다 (\"묶음에 담기\"가 아니다 — 그런 공개 API 는 존재하지 않는다. reviewSubmissionItems 는 appStoreVersion 계열 관계만 받는다, 2026-07 실측). 이미 승인된 적 있는 상품의 변경분 제출용. **앱 첫 심사** 상품은 Apple 이 \"no pending version\" 409 로 거부한다 — 그 경우 ASC 웹 버전 페이지의 \"앱 내 구입 및 구독\" 섹션에서 담아 버전과 함께 제출해야 한다 (도구가 에러에 안내 첨부). 상품 상태가 READY_TO_SUBMIT 이어야 한다 (MISSING_METADATA 면 appstore_update_product_localization 먼저). ⚠️ 안전 가드: confirm 생략/false 면 아무것도 바꾸지 않고 dry-run preview 만 반환한다. 사용자 명시 승인 후 confirm: true 로 재호출.", "execution": { "taskSupport": "forbidden" }, + "confirm": { + "description": "true 명시 시에만 실제 실행. 생략/false 면 dry-run preview 만 반환 (비가역·공개 사고 차단).", + "type": "boolean" + }, "productId": { "description": "상품 ID (appstore_list_products 결과)", "type": "string" - "name": "appstore_add_product_to_review" + "name": "appstore_add_product_to_review", + "title": "App Store: Add product to review" }
--- pinned/appstore_add_version_to_review_submission +++ observed/appstore_add_version_to_review_submission { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Add version to review submission" + }, "description": "이미 존재하는 심사 묶음에 앱 버전을 항목으로 추가한다 (POST /reviewSubmissionItems). ⚠️ 앱 첫 심사 필수 절차 — 웹에서 IAP/구독을 담으면 \"상품만 든 묶음\"이 새로 생기는데, 그대로 제출하면 409 \"an appStoreVersions must be included in this review submission\" 로 막힌다. reviewSubmissionItems 는 상품 관계는 거부하지만 appStoreVersion 관계는 받으므로, 버전을 이 묶음으로 옮기면 된다. 버전이 다른 묶음에 물려 있으면 먼저 풀 것: 미제출 묶음이면 appstore_remove_review_submission_item, 제출된 묶음이면 항목 제거가 막히므로 appstore_cancel_review 로 묶음째 취소. 추가 후 appstore_submit_for_review 로 제출하면 버전+상품이 한 묶음으로 나간다.", "execution": { "taskSupport": "forbidden" - "name": "appstore_add_version_to_review_submission" + "name": "appstore_add_version_to_review_submission", + "title": "App Store: Add version to review submission" }
--- pinned/appstore_attach_build +++ observed/appstore_attach_build { - "description": "App Store 버전에 업로드된 빌드를 연결 — PATCH /v1/appStoreVersions/{id}/relationships/build. TestFlight에 업로드되어 processingState=VALID 상태인 빌드만 연결 가능. 편집 가능한 버전(PREPARE_FOR_SUBMISSION 등)에서만 변경됨. buildId는 appstore_list_builds 결과 사용.", + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Attach build" + }, + "description": "App Store 버전에 업로드된 빌드를 연결 — PATCH /v1/appStoreVersions/{id}/relationships/build. TestFlight에 업로드되어 processingState=VALID 상태인 빌드만 연결 가능. 편집 가능한 버전(PREPARE_FOR_SUBMISSION 등)에서만 변경됨. buildId 는 appstore_list_builds 결과. 생략하면 최신 VALID 빌드를 자동 선택한다 — versionId 로 appId 역추적 → processingState=VALID 만 필터 → buildNumber 최대값 → attach (PROCESSING 빌드 오연결 차단). minBuildNumber 로 자동 선택의 floor 지정 가능 (예: 1.4.x 빌드만).", "execution": { "taskSupport": "forbidden" }, - "description": "빌드 ID (appstore_list_builds 결과)", + "description": "빌드 ID (appstore_list_builds 결과). 생략 시 최신 VALID 빌드 자동 선택", "type": "string" }, + "minBuildNumber": { + "description": "buildId 생략 시 자동 선택 후보의 최소 buildNumber (예: 186 — 이전 빌드 무시)", + "type": "integer" + }, "versionId": { "description": "App Store 버전 ID (appstore_list_versions 또는 appstore_create_version 결과)", "type": "string" - "versionId", - "buildId" + "versionId" ], "type": "object" }, - "name": "appstore_attach_build" + "name": "appstore_attach_build", + "title": "App Store: Attach build" }
--- pinned/appstore_beta_status +++ observed/appstore_beta_status { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "App Store: Beta status" + }, "description": "TestFlight 외부 테스트 제출 전 점검 — 읽기 전용. 빌드의 internal/external 상태, 베타 심사 제출 상태, What to Test 가 채워진 로케일을 보여준다. appId 를 함께 주면 앱 단위 항목(베타 심사 연락처·데모 계정, 테스트 정보 로케일)까지 검사해 빠진 필드를 알려준다. 외부 배포가 막히면 여기부터 본다 — 대부분 수출 규정 미선언이나 심사 정보 공란이다.", "execution": { "taskSupport": "forbidden" - "name": "appstore_beta_status" + "name": "appstore_beta_status", + "title": "App Store: Beta status" }
--- pinned/appstore_cancel_review +++ observed/appstore_cancel_review { - "description": "App Store 심사 제출을 철회 — WAITING_FOR_REVIEW 상태에서만 가능. PATCH attributes.canceled=true → state 가 CANCELING 으로 바뀌고 수십 초 뒤 COMPLETE(항목 REMOVED), 버전은 편집 가능 상태로 복귀해 메타데이터/빌드 수정 가능. CANCELING 은 비동기라 호출 직후엔 아직 COMPLETE 가 아니다 — 이어서 작업하려면 상태를 폴링할 것. ⚠️ IN_REVIEW 이상이면 Apple API가 409로 거부함 — 이 경우 App Store Connect 웹에서 직접 처리하거나 심사 결과를 기다려야 함. 제출된 묶음에서 항목만 빼내는 것(removed)은 막히므로, 버전을 다른 묶음으로 옮기려면 이 도구로 묶음째 취소한다. 철회 후 수정 완료 시 appstore_submit_for_review로 재제출 가능.", + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Cancel review" + }, + "description": "App Store 심사 제출을 철회 — WAITING_FOR_REVIEW 상태에서만 가능. PATCH attributes.canceled=true → state 가 CANCELING 으로 바뀌고 수십 초 뒤 COMPLETE(항목 REMOVED), 버전은 편집 가능 상태로 복귀해 메타데이터/빌드 수정 가능. CANCELING 은 비동기라 호출 직후엔 아직 COMPLETE 가 아니다 — 이어서 작업하려면 상태를 폴링할 것. ⚠️ IN_REVIEW 이상이면 Apple API가 409로 거부함 — 이 경우 App Store Connect 웹에서 직접 처리하거나 심사 결과를 기다려야 함. 제출된 묶음에서 항목만 빼내는 것(removed)은 막히므로, 버전을 다른 묶음으로 옮기려면 이 도구로 묶음째 취소한다. 철회 후 수정 완료 시 appstore_submit_for_review로 재제출 가능. ⚠️ 안전 가드: confirm 생략/false 면 아무것도 바꾸지 않고 dry-run preview 만 반환한다. 사용자 명시 승인 후 confirm: true 로 재호출.", "execution": { "taskSupport": "forbidden" }, + "confirm": { + "description": "true 명시 시에만 실제 실행. 생략/false 면 dry-run preview 만 반환 (비가역·공개 사고 차단).", + "type": "boolean" + }, "versionId": { "description": "App Store 버전 ID (appstore_list_versions 결과)", "type": "string" - "name": "appstore_cancel_review" + "name": "appstore_cancel_review", + "title": "App Store: Cancel review" }
--- pinned/appstore_check_submission_risks +++ observed/appstore_check_submission_risks { - "description": "App Store 제출 전 위험 요소를 자동으로 점검합니다. 블로커(반드시 수정)와 경고(권장 수정)로 분류하여 반환합니다. 점검 항목: 메타데이터 완성도(설명/What's New/키워드), 스크린샷, TestFlight 빌드, 개인정보처리방침 URL. App Store 인증이 필요합니다 (appstore_* 도구 사용 가능 상태여야 함).", + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "App Store: Check submission risks" + }, + "description": "App Store 제출 전 위험 요소를 자동으로 점검합니다. 블로커(반드시 수정)와 경고(권장 수정)로 분류하여 반환합니다. 점검 항목: 메타데이터 완성도(설명/What's New/키워드), 스크린샷, TestFlight 빌드, 개인정보처리방침 URL. 2026년 9월 필수화된 소셜 미디어 연령등급 응답을 확인하고, 기대 기능 값을 주면 App Store Connect 응답과 비교합니다. App Store 인증이 필요합니다 (appstore_* 도구 사용 가능 상태여야 함).", "execution": { "taskSupport": "forbidden" }, + }, + "socialMediaAgeRestricted": { + "description": "소셜 미디어 기능이 13세 미만에게 비활성화되는지에 대한 프로젝트 사실", + "type": "boolean" + }, + "socialMediaCapability": { + "description": "앱이 소셜 피드·UGC 확산 기능을 제공하는지에 대한 프로젝트 사실", + "type": "boolean" } }, "required": [ - "name": "appstore_check_submission_risks" + "name": "appstore_check_submission_risks", + "title": "App Store: Check submission risks" }
--- pinned/appstore_create_app_info_localization +++ observed/appstore_create_app_info_localization { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Create app info localization" + }, "description": "appInfo 로컬라이제이션(스토어 언어) 추가 — POST /appInfoLocalizations. 편집 가능 appInfo를 자동으로 찾아 새 locale의 앱 이름/부제/개인정보 URL을 생성. 이미 존재하는 locale이면 409 DUPLICATE — 그땐 appstore_update_app_info_localization 사용. 생성하면 같은 locale의 버전 로컬라이제이션(설명/키워드/whatsNew)도 함께 생길 수 있음(2026-07 실측) — 내용 채우기는 appstore_update_localization. 제한: name 30자, subtitle 30자. locale 예: \"en-US\", \"ja\", \"zh-Hans\", \"zh-Hant\".", "execution": { "taskSupport": "forbidden" - "name": "appstore_create_app_info_localization" + "name": "appstore_create_app_info_localization", + "title": "App Store: Create app info localization" }
--- pinned/appstore_create_inapp_purchase +++ observed/appstore_create_inapp_purchase { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Create inapp purchase" + }, "description": "App Store에 일회성 인앱 구매(IAP)를 생성 — CONSUMABLE (소비성) / NON_CONSUMABLE (비소비성). 생성 후 App Store Connect에서 스크린샷·리뷰 노트를 추가해야 심사 제출 가능.", "execution": { "taskSupport": "forbidden" + "maxLength": 255, + "pattern": "^[A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*$", "type": "string" }, "currency": { - "name": "appstore_create_inapp_purchase" + "name": "appstore_create_inapp_purchase", + "title": "App Store: Create inapp purchase" }
--- pinned/appstore_create_subscription +++ observed/appstore_create_subscription { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Create subscription" + }, "description": "App Store에 자동 갱신 구독을 생성 — Subscription Group 자동 생성 포함. 생성 후 App Store Connect에서 스크린샷·리뷰 노트를 추가해야 심사 제출 가능.", "execution": { "taskSupport": "forbidden" + "maxLength": 255, + "pattern": "^[A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*$", "type": "string" }, "currency": { - "name": "appstore_create_subscription" + "name": "appstore_create_subscription", + "title": "App Store: Create subscription" }
--- pinned/appstore_create_version +++ observed/appstore_create_version { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Create version" + }, "description": "App Store 새 버전 레코드 생성 — POST /v1/appStoreVersions. 새 versionString(예: \"1.2.3\")으로 PREPARE_FOR_SUBMISSION 상태의 버전을 만듦. buildId를 함께 주면 생성과 동시에 빌드 연결. 나중에 붙이려면 appstore_attach_build 사용. releaseType: MANUAL(개발자가 출시) / AFTER_APPROVAL(승인 후 자동) / SCHEDULED(earliestReleaseDate 필요).", "execution": { "taskSupport": "forbidden" - "name": "appstore_create_version" + "name": "appstore_create_version", + "title": "App Store: Create version" }
--- pinned/appstore_declare_encryption +++ observed/appstore_declare_encryption { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Declare encryption" + }, "description": "수출 규정(암호화) 선언을 만들고 선택한 빌드에 연결한다 — POST /v1/appEncryptionDeclarations. Info.plist 의 ITSAppUsesNonExemptEncryption 이 있으면 보통 이 선언이 필요 없다 — 그게 없어서 ASC 가 \"수출 규정 정보 누락\"으로 제출을 막을 때 쓰는 경로다. ⚠️ 법적 신고 성격의 선언이다. 값은 반드시 사용자에게 확인받고 넣을 것.", "execution": { "taskSupport": "forbidden" - "name": "appstore_declare_encryption" + "name": "appstore_declare_encryption", + "title": "App Store: Declare encryption" }
--- pinned/appstore_delete_preview +++ observed/appstore_delete_preview { + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Delete preview" + }, "description": "미리보기 동영상 또는 세트를 삭제한다 — DELETE /v1/appPreviews/{id} 또는 /appPreviewSets/{id}. ⚠️ 되돌릴 수 없다. 세트를 지우면 그 안의 동영상이 모두 사라진다. confirm 필요.", "execution": { "taskSupport": "forbidden" - "name": "appstore_delete_preview" + "name": "appstore_delete_preview", + "title": "App Store: Delete preview" }
--- pinned/appstore_delete_product +++ observed/appstore_delete_product { - "description": "⚠️ 비가역. App Store IAP 상품 삭제. MISSING_METADATA / WAITING_FOR_REVIEW 상태만 가능 — 이미 승인(READY_FOR_SALE)된 상품은 Console에서 \"Remove from sale\" 해야 함.", + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Delete product" + }, + "description": "⚠️ 비가역. App Store IAP 상품 삭제. MISSING_METADATA / WAITING_FOR_REVIEW 상태만 가능 — 이미 승인(READY_FOR_SALE)된 상품은 Console에서 \"Remove from sale\" 해야 함. ⚠️ 안전 가드: confirm 생략/false 면 아무것도 바꾸지 않고 dry-run preview 만 반환한다. 사용자 명시 승인 후 confirm: true 로 재호출.", "execution": { "taskSupport": "forbidden" }, + "maxLength": 255, + "pattern": "^[A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*$", "type": "string" }, + "confirm": { + "description": "true 명시 시에만 실제 실행. 생략/false 면 dry-run preview 만 반환 (비가역·공개 사고 차단).", + "type": "boolean" + }, "productId": { "description": "상품 ID", "type": "string" - "name": "appstore_delete_product" + "name": "appstore_delete_product", + "title": "App Store: Delete product" }
--- pinned/appstore_delete_screenshot +++ observed/appstore_delete_screenshot { - "description": "App Store 개별 스크린샷 삭제", + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Delete screenshot" + }, + "description": "App Store 개별 스크린샷 삭제 ⚠️ 안전 가드: confirm 생략/false 면 아무것도 바꾸지 않고 dry-run preview 만 반환한다. 사용자 명시 승인 후 confirm: true 로 재호출.", "execution": { "taskSupport": "forbidden" }, + "confirm": { + "description": "true 명시 시에만 실제 실행. 생략/false 면 dry-run preview 만 반환 (비가역·공개 사고 차단).", + "type": "boolean" + }, "screenshotId": { "description": "스크린샷 ID (appstore_list_screenshots 결과)", "type": "string" - "name": "appstore_delete_screenshot" + "name": "appstore_delete_screenshot", + "title": "App Store: Delete screenshot" }
--- pinned/appstore_delete_screenshot_set +++ observed/appstore_delete_screenshot_set { - "description": "App Store 스크린샷 셋 전체 삭제 (디스플레이 타입 교체 시 먼저 정리)", + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Delete screenshot set" + }, + "description": "App Store 스크린샷 셋 전체 삭제 (디스플레이 타입 교체 시 먼저 정리) ⚠️ 안전 가드: confirm 생략/false 면 아무것도 바꾸지 않고 dry-run preview 만 반환한다. 사용자 명시 승인 후 confirm: true 로 재호출.", "execution": { "taskSupport": "forbidden" }, + "confirm": { + "description": "true 명시 시에만 실제 실행. 생략/false 면 dry-run preview 만 반환 (비가역·공개 사고 차단).", + "type": "boolean" + }, "setId": { "description": "스크린샷 셋 ID (appstore_list_screenshots 결과)", "type": "string" - "name": "appstore_delete_screenshot_set" + "name": "appstore_delete_screenshot_set", + "title": "App Store: Delete screenshot set" }
--- pinned/appstore_get_age_rating +++ observed/appstore_get_age_rating { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "App Store: Get age rating" + }, "description": "앱의 연령 등급 설문(ageRatingDeclaration) 현재 값을 읽는다 — 읽기 전용. appInfo 에 딸린 단일 리소스이며, 편집 가능한 appInfo 를 자동으로 고른다. 수정 전에 이걸로 현재 답변을 먼저 확인할 것.", "execution": { "taskSupport": "forbidden" - "name": "appstore_get_age_rating" + "name": "appstore_get_age_rating", + "title": "App Store: Get age rating" }
--- pinned/appstore_get_app +++ observed/appstore_get_app { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "App Store: Get app" + }, "description": "App Store Connect 앱 상세 정보", "execution": { "taskSupport": "forbidden" - "name": "appstore_get_app" + "name": "appstore_get_app", + "title": "App Store: Get app" }
--- pinned/appstore_get_app_info +++ observed/appstore_get_app_info { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "App Store: Get app info" + }, "description": "App Store 앱 정보 (카테고리, 연령 등급, state). state=READY_FOR_DISTRIBUTION이 라이브, 그 외가 편집 가능 appInfo.", "execution": { "taskSupport": "forbidden" - "name": "appstore_get_app_info" + "name": "appstore_get_app_info", + "title": "App Store: Get app info" }
--- pinned/appstore_get_availability +++ observed/appstore_get_availability { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "App Store: Get availability" + }, "description": "앱의 판매 지역 상태를 읽는다 — GET /v1/apps/{id}/appAvailabilityV2. 판매 중/중지 지역 수와 신규 지역 자동 포함 여부를 보여준다. includeTerritories=true 면 지역별 행(id·available·releaseDate)까지 — 이 id 가 변경 도구의 입력이다.", "execution": { "taskSupport": "forbidden" - "name": "appstore_get_availability" + "name": "appstore_get_availability", + "title": "App Store: Get availability" }
--- pinned/appstore_get_finance_report +++ observed/appstore_get_finance_report { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "App Store: Get finance report" + }, "description": "재무(정산) 리포트 — GET /v1/financeReports. 실제로 지급되는 금액 기준이라 Sales and Trends(판매 시점 집계)와 숫자가 다를 수 있다. ⚠️ **reportDate 는 Apple 회계월이다** — 달력월과 어긋난다(회계연도가 9월 말에 시작). 요청한 달과 다른 기간이 돌아오면 버그가 아니라 이것이다. 매출 건수를 세는 목적이면 appstore_get_sales_report(달력 날짜 기준)를 쓰는 편이 낫다. regionCode 는 ZZ(전 지역 통합)가 기본이고, FINANCE_DETAIL 은 보통 Z1 을 쓴다. 컬럼 구성이 리포트마다 달라 파싱한 행을 그대로 돌려준다.", "execution": { "taskSupport": "forbidden" - "name": "appstore_get_finance_report" + "name": "appstore_get_finance_report", + "title": "App Store: Get finance report" }
--- pinned/appstore_get_metadata +++ observed/appstore_get_metadata { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "App Store: Get metadata" + }, "description": "App Store 버전 메타데이터 (설명문, 키워드, What's New)", "execution": { "taskSupport": "forbidden" - "name": "appstore_get_metadata" + "name": "appstore_get_metadata", + "title": "App Store: Get metadata" }
--- pinned/appstore_get_review_notes +++ observed/appstore_get_review_notes { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "App Store: Get review notes" + }, "description": "App Store 심사 리뷰어 노트(Notes for App Review) 조회. 현재 등록된 notes, contactEmail 확인용.", "execution": { "taskSupport": "forbidden" - "name": "appstore_get_review_notes" + "name": "appstore_get_review_notes", + "title": "App Store: Get review notes" }
--- pinned/appstore_get_sales_report +++ observed/appstore_get_sales_report { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "App Store: Get sales report" + }, "description": "Sales and Trends 리포트 = **실매출의 기준선** — GET /v1/salesReports (gzip TSV 를 파싱해 돌려준다). 분석 이벤트(GA4 in_app_purchase 등)로 매출을 세면 안 되는 이유가 여기 있다: TestFlight·Xcode 설치의 결제는 **sandbox 라 청구가 0원인데도** 클라이언트에는 성공한 결제로 보여 이벤트가 그대로 나간다. 이 리포트에는 sandbox 가 애초에 들어오지 않으므로, 둘을 비교하면 \"진짜 돈이 들어온 건수\"가 곧바로 갈린다. ⚠️ **Developer Proceeds 는 1개당 금액이다** — 총액은 units 를 곱해야 한다(이 도구는 곱해서 준다). ⚠️ 환불은 units 가 **음수**로 들어와 합계에서 상쇄된다. 즉 합계는 순매출이다. ⚠️ 데이터가 없는 날짜는 Apple 이 404 를 주므로 datesWithoutData 로 따로 돌려준다 — \"매출 0\" 과 \"리포트 미생성/설정 오류\"를 섞지 말 것. 당일치는 보통 아직 없다. vendorNumber 는 ~/.mimi-seed/appstore.json 에 저장해두면 생략 가능. ⚠️ **리포트는 요구 롤이 다르다** — Admin/Finance/Sales and Reports 중 하나여야 하고, 배포에 흔히 쓰는 App Manager 키는 여기서만 403 이 난다. 발급된 키의 롤은 수정할 수 없으므로, 읽기 전용 Finance 키를 발급해 appstore.json 의 **reportsKey** 에 넣으면 배포 키를 건드리지 않아도 된다.", "execution": { "taskSupport": "forbidden" - "name": "appstore_get_sales_report" + "name": "appstore_get_sales_report", + "title": "App Store: Get sales report" }
+ tool added: appstore_get_weekly_insight
--- pinned/appstore_list_app_info_localizations +++ observed/appstore_list_app_info_localizations { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "App Store: List app info localizations" + }, "description": "편집 가능한 appInfo의 로컬라이제이션 목록 조회 — 앱 이름(name), 부제(subtitle), 개인정보 URL/텍스트. appInfo.relationships.appInfoLocalizations가 빈 배열로 오는 케이스를 우회하려고 /appInfos/{id}/appInfoLocalizations 직접 호출. locale을 주면 해당 언어만 반환 (예: \"ko\", \"en-US\"). ※ versionLocalization(설명/키워드/whatsNew)과 다름 — 그건 appstore_get_metadata 사용.", "execution": { "taskSupport": "forbidden" - "name": "appstore_list_app_info_localizations" + "name": "appstore_list_app_info_localizations", + "title": "App Store: List app info localizations" }
--- pinned/appstore_list_apps +++ observed/appstore_list_apps { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "App Store: List apps" + }, "description": "App Store Connect 앱 목록 조회", "execution": { "taskSupport": "forbidden" - "name": "appstore_list_apps" + "name": "appstore_list_apps", + "title": "App Store: List apps" }
--- pinned/appstore_list_beta_groups +++ observed/appstore_list_beta_groups { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "App Store: List beta groups" + }, "description": "TestFlight 베타 그룹 목록", "execution": { "taskSupport": "forbidden" - "name": "appstore_list_beta_groups" + "name": "appstore_list_beta_groups", + "title": "App Store: List beta groups" }
--- pinned/appstore_list_builds +++ observed/appstore_list_builds { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "App Store: List builds" + }, "description": "TestFlight 빌드 목록", "execution": { "taskSupport": "forbidden" - "name": "appstore_list_builds" + "name": "appstore_list_builds", + "title": "App Store: List builds" }
--- pinned/appstore_list_previews +++ observed/appstore_list_previews { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "App Store: List previews" + }, "description": "버전 로케일의 미리보기 동영상 세트를 조회한다 — 읽기 전용. 세트별 previewType 과 각 동영상의 처리 상태(assetDeliveryState)·포스터 프레임·videoUrl 을 보여준다. 업로드 직후 인코딩이 끝났는지 확인할 때도 이걸 쓴다.", "execution": { "taskSupport": "forbidden" - "name": "appstore_list_previews" + "name": "appstore_list_previews", + "title": "App Store: List previews" }
--- pinned/appstore_list_product_localizations +++ observed/appstore_list_product_localizations { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "App Store: List product localizations" + }, "description": "App Store IAP/구독 상품의 현지화(표시 이름·설명) 목록 조회. locale / name / description / state 반환.", "execution": { "taskSupport": "forbidden" - "name": "appstore_list_product_localizations" + "name": "appstore_list_product_localizations", + "title": "App Store: List product localizations" }
--- pinned/appstore_list_products +++ observed/appstore_list_products { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "App Store: List products" + }, "description": "App Store의 모든 IAP 상품(구독 + 일회성) 통합 조회. productId / internalId / name / status / type 반환.", "execution": { "taskSupport": "forbidden" - "name": "appstore_list_products" + "name": "appstore_list_products", + "title": "App Store: List products" }
--- pinned/appstore_list_review_submissions +++ observed/appstore_list_review_submissions { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "App Store: List review submissions" + }, "description": "App Store 심사 제출 묶음(reviewSubmissions) + 내부 항목 조회 — 읽기 전용. 각 묶음의 state(READY_FOR_REVIEW=초안 / WAITING_FOR_REVIEW=큐 / UNRESOLVED_ISSUES=거절 미해결 / COMPLETE) 와 항목별 state·연결 리소스(appStoreVersion 이면 versionString 포함)를 보여준다. 재제출이 \"appStoreVersions ... is not in valid state\" 로 막힐 때 첫 번째로 볼 것 — 진범은 대개 UNRESOLVED_ISSUES 묶음이 버전을 REJECTED 항목으로 물고 있는 것이다 (버전 자체는 PREPARE_FOR_SUBMISSION 으로 멀쩡해 보인다, 2026-07 실측). 해제는 appstore_remove_review_submission_item.", "execution": { "taskSupport": "forbidden" - "name": "appstore_list_review_submissions" + "name": "appstore_list_review_submissions", + "title": "App Store: List review submissions" }
--- pinned/appstore_list_reviews +++ observed/appstore_list_reviews { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "App Store: List reviews" + }, "description": "App Store 받은 고객 리뷰 조회 (최신순). response 필드에 개발자 답변 존재 여부와 내용이 함께 포함됨 (없으면 null). territory(예: KOR/USA — ISO 3166 alpha-3) / rating(1~5)으로 필터 가능.", "execution": { "taskSupport": "forbidden" - "name": "appstore_list_reviews" + "name": "appstore_list_reviews", + "title": "App Store: List reviews" }
--- pinned/appstore_list_screenshots +++ observed/appstore_list_screenshots { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "App Store: List screenshots" + }, "description": "App Store 스크린샷 셋 + 이미지 목록 조회 (로컬라이제이션 단위). 디스플레이 타입별로 그룹핑됨", "execution": { "taskSupport": "forbidden" - "name": "appstore_list_screenshots" + "name": "appstore_list_screenshots", + "title": "App Store: List screenshots" }
--- pinned/appstore_list_versions +++ observed/appstore_list_versions { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "App Store: List versions" + }, "description": "App Store 버전 목록 (심사 상태 포함)", "execution": { "taskSupport": "forbidden" - "name": "appstore_list_versions" + "name": "appstore_list_versions", + "title": "App Store: List versions" }
--- pinned/appstore_notify_beta_testers +++ observed/appstore_notify_beta_testers { + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Notify beta testers" + }, "description": "이미 배포된 빌드에 대해 테스터에게 알림을 다시 보낸다 — POST /v1/buildBetaNotifications. 자동 알림(autoNotifyEnabled)이 꺼져 있거나, 배포 후 다시 알리고 싶을 때. ⚠️ 테스터 전원에게 푸시/메일이 나간다. confirm 필요.", "execution": { "taskSupport": "forbidden" - "name": "appstore_notify_beta_testers" + "name": "appstore_notify_beta_testers", + "title": "App Store: Notify beta testers" }
--- pinned/appstore_phased_release +++ observed/appstore_phased_release { + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Phased release" + }, "description": "iOS 단계적 출시(7일 램프)를 제어한다 — appStoreVersionPhasedReleases. action: status(조회) / enable(켜기·PAUSED면 재개) / pause(일시중지) / resume(재개) / complete(즉시 전체 공개) / disable(단계적 출시 제거). Play 의 userFraction·halted 에 해당하는 iOS 쪽 장치다. ⚠️ complete 와 disable 은 남은 사용자 전체에게 즉시 공개되며 되돌릴 수 없다 — confirm: true 필요. pause/resume/enable 은 되돌릴 수 있어 confirm 없이 실행된다.", "execution": { "taskSupport": "forbidden" - "name": "appstore_phased_release" + "name": "appstore_phased_release", + "title": "App Store: Phased release" }
--- pinned/appstore_plan_release +++ observed/appstore_plan_release { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "App Store: Plan release" + }, "description": "App Store 배포 플랜 — 편집 가능한 버전/빌드 attach/메타/스크린샷/정책 위험을 한 번에 점검하고 체크리스트로 반환합니다 (read-only). ⚠️ AI 호출자 지시: 응답의 미완료 항목을 반드시 TodoWrite로 사용자에게 먼저 보여주고, 사용자 동의 후 단계별로 기존 도구(appstore_update_localization, appstore_update_whats_new, appstore_submit_for_review 등)를 호출하세요. submit_for_review는 비가역이므로 반드시 명시 동의 필요.", "execution": { "taskSupport": "forbidden" - "name": "appstore_plan_release" + "name": "appstore_plan_release", + "title": "App Store: Plan release" }
--- pinned/appstore_release_status +++ observed/appstore_release_status { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "App Store: Release status" + }, "description": "버전의 출시 상태를 한 번에 읽는다 — 읽기 전용. appStoreState(PENDING_DEVELOPER_RELEASE / READY_FOR_SALE …), releaseType(MANUAL / AFTER_APPROVAL / SCHEDULED), earliestReleaseDate, 그리고 단계적 출시가 켜져 있으면 그 상태(ACTIVE/PAUSED/COMPLETE)와 현재 며칠째인지. 출시 관련 쓰기 도구를 부르기 전에 이걸로 먼저 확인할 것.", "execution": { "taskSupport": "forbidden" - "name": "appstore_release_status" + "name": "appstore_release_status", + "title": "App Store: Release status" }
--- pinned/appstore_release_version +++ observed/appstore_release_version { + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Release version" + }, "description": "심사를 통과해 개발자 출시 대기(PENDING_DEVELOPER_RELEASE) 중인 버전을 지금 출시한다 — POST /v1/appStoreVersionReleaseRequests. 콘솔의 \"이 버전 출시\" 버튼과 같은 동작. ⚠️ 비가역: 실행 즉시 App Store 에 공개된다. 되돌리려면 새 버전을 내거나 판매 중단해야 한다. 안전 가드: confirm 생략/false 면 현재 상태만 보여주는 dry-run. releaseType=AFTER_APPROVAL 로 만든 버전은 승인 시 자동 출시되므로 이 도구가 필요 없다 — MANUAL 로 대기 중인 버전용이다.", "execution": { "taskSupport": "forbidden" - "name": "appstore_release_version" + "name": "appstore_release_version", + "title": "App Store: Release version" }
--- pinned/appstore_remove_review_submission_item +++ observed/appstore_remove_review_submission_item { - "description": "심사 제출 묶음에서 항목을 제거한다 (removed=true PATCH) — ASC 웹 \"재제출\" 버튼이 내부적으로 하는 동작. 거절된 옛 묶음(UNRESOLVED_ISSUES)이 버전을 물고 있어 재제출이 ENTITY_STATE_INVALID 로 막힐 때 해제용. 항목이 풀리면 옛 묶음은 COMPLETE 로 정리된다. itemId 는 appstore_list_review_submissions 결과. (appstore_submit_for_review 는 이 해제를 자동으로 시도한다 — 수동 개입이 필요할 때만 직접 호출.)", + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Remove review submission item" + }, + "description": "심사 제출 묶음에서 항목을 제거한다 (removed=true PATCH) — ASC 웹 \"재제출\" 버튼이 내부적으로 하는 동작. 거절된 옛 묶음(UNRESOLVED_ISSUES)이 버전을 물고 있어 재제출이 ENTITY_STATE_INVALID 로 막힐 때 해제용. 항목이 풀리면 옛 묶음은 COMPLETE 로 정리된다. itemId 는 appstore_list_review_submissions 결과. (appstore_submit_for_review 는 이 해제를 자동으로 시도한다 — 수동 개입이 필요할 때만 직접 호출.) ⚠️ 안전 가드: confirm 생략/false 면 아무것도 바꾸지 않고 dry-run preview 만 반환한다. 사용자 명시 승인 후 confirm: true 로 재호출.", "execution": { "taskSupport": "forbidden" }, + "confirm": { + "description": "true 명시 시에만 실제 실행. 생략/false 면 dry-run preview 만 반환 (비가역·공개 사고 차단).", + "type": "boolean" + }, "itemId": { "description": "reviewSubmissionItem ID (appstore_list_review_submissions 결과)", "type": "string" - "name": "appstore_remove_review_submission_item" + "name": "appstore_remove_review_submission_item", + "title": "App Store: Remove review submission item" }
--- pinned/appstore_reply_review +++ observed/appstore_reply_review { - "description": "App Store 고객 리뷰에 개발자 답변을 등록 (또는 갱신). 동일 리뷰에 한 번만 답변 가능 — 기존 답변이 있으면 Apple이 새 응답으로 대체함. reviewId는 appstore_list_reviews 결과의 id. 답변 본문은 5970자 이내.", + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Reply review" + }, + "description": "App Store 고객 리뷰에 개발자 답변을 등록 (또는 갱신). 동일 리뷰에 한 번만 답변 가능 — 기존 답변이 있으면 Apple이 새 응답으로 대체함. reviewId는 appstore_list_reviews 결과의 id. 답변 본문은 5970자 이내. ⚠️ 안전 가드: confirm 생략/false 면 아무것도 바꾸지 않고 dry-run preview 만 반환한다. 사용자 명시 승인 후 confirm: true 로 재호출.", "execution": { "taskSupport": "forbidden" }, + "confirm": { + "description": "true 명시 시에만 실제 실행. 생략/false 면 dry-run preview 만 반환 (비가역·공개 사고 차단).", + "type": "boolean" + }, "responseBody": { "description": "답변 본문 (5970자 이내)", "type": "string" - "name": "appstore_reply_review" + "name": "appstore_reply_review", + "title": "App Store: Reply review" }
--- pinned/appstore_set_beta_group_build +++ observed/appstore_set_beta_group_build { + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Set beta group build" + }, "description": "베타 그룹에 빌드를 붙이거나 뗀다 — POST/DELETE /v1/betaGroups/{id}/relationships/builds. ⚠️ 외부 그룹에 붙이는 것은 **실제 배포**다 (심사 통과 후에만 가능). 떼면 테스터가 더 이상 받지 못한다. groupId 는 appstore_list_beta_groups 결과. confirm 생략/false 면 dry-run.", "execution": { "taskSupport": "forbidden" - "name": "appstore_set_beta_group_build" + "name": "appstore_set_beta_group_build", + "title": "App Store: Set beta group build" }
--- pinned/appstore_set_territory_availability +++ observed/appstore_set_territory_availability { + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Set territory availability" + }, "description": "지역별 판매 여부·출시일을 바꾼다 — PATCH /v1/territoryAvailabilities/{id}. id 는 appstore_get_availability(includeTerritories=true) 결과에서 가져올 것 — 지역 코드를 추측해 넣지 말 것. 한 지역이 실패해도 나머지는 계속 진행하고, 지역별 성공/실패를 그대로 보고한다. ⚠️ available=false 는 그 지역에서 앱을 내리는 동작이다.", "execution": { "taskSupport": "forbidden" - "name": "appstore_set_territory_availability" + "name": "appstore_set_territory_availability", + "title": "App Store: Set territory availability" }
--- pinned/appstore_submit_beta_review +++ observed/appstore_submit_beta_review { + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Submit beta review" + }, "description": "빌드를 TestFlight 베타 심사에 제출한다 — POST /v1/betaAppReviewSubmissions. 외부 테스터에게 배포하려면 이 심사를 통과해야 한다 (내부 테스터는 불필요). 사전 조건: 외부 상태가 READY_FOR_BETA_SUBMISSION, What to Test 채움, 베타 심사 정보 채움. appstore_beta_status 로 먼저 점검할 것. confirm 생략/false 면 현재 상태만 보여주는 dry-run.", "execution": { "taskSupport": "forbidden" - "name": "appstore_submit_beta_review" + "name": "appstore_submit_beta_review", + "title": "App Store: Submit beta review" }
--- pinned/appstore_submit_for_review +++ observed/appstore_submit_for_review { + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Submit for review" + }, "description": "App Store 버전을 심사에 제출 — 새 reviewSubmissions API 사용 (옛 /appStoreVersionSubmissions는 2024-01 deprecated). 내부 흐름: POST /reviewSubmissions(또는 CREATED 상태 재사용) → POST /reviewSubmissionItems(version attach) → PATCH submitted=true. appId와 platform은 versionId에서 자동 조회 — 별도 입력 불필요. ⚠️ 비가역 작업: 제출 후엔 Apple 심사가 시작되며, 메타데이터/스크린샷/빌드를 더 못 바꿈 (REJECTED/METADATA_REJECTED 시 다시 편집 가능). 안전 가드: confirm 생략/false 시 dry-run preview 만 반환 (versionString·빌드·whatsNew 발췌). 실제 제출은 confirm: true 로 재호출. 사전 조건: 버전이 PREPARE_FOR_SUBMISSION 또는 DEVELOPER_REJECTED 상태, 빌드 attached, 모든 필수 메타데이터 채워짐. 거절된 옛 묶음(UNRESOLVED_ISSUES)이 버전을 물고 있어 attach 가 막히면 자동으로 항목을 해제(removed=true)하고 재시도한다 — 진단은 appstore_list_review_submissions. appstore_check_submission_risks로 사전 점검 권장.", "execution": { "taskSupport": "forbidden" - "name": "appstore_submit_for_review" + "name": "appstore_submit_for_review", + "title": "App Store: Submit for review" }
--- pinned/appstore_update_age_rating +++ observed/appstore_update_age_rating { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Update age rating" + }, "description": "연령 등급 설문을 갱신한다 — PATCH /v1/ageRatingDeclarations/{id}. 넘긴 필드만 바뀐다 (부분 갱신). 전체를 다시 보낼 필요 없다. 미완성이면 심사 제출이 막히므로 첫 출시 전 반드시 채워야 한다. Play 의 콘텐츠 등급 설문과 달리 Apple 은 이렇게 API 로 답변할 수 있다.", "execution": { "taskSupport": "forbidden" + "socialMedia": { + "description": "UGC를 피드·탐색 방식으로 재배포·확산·상호작용하는 소셜 미디어 기능", + "type": "boolean" + }, + "socialMediaAgeRestricted": { + "description": "소셜 미디어 기능을 13세 미만 사용자에게 비활성화", + "type": "boolean" + }, "unrestrictedWebAccess": { "description": "제한 없는 웹 접근", "type": "boolean" - "name": "appstore_update_age_rating" + "name": "appstore_update_age_rating", + "title": "App Store: Update age rating" }
--- pinned/appstore_update_app_info_localization +++ observed/appstore_update_app_info_localization { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Update app info localization" + }, "description": "appInfo 로컬라이제이션(앱 이름/부제/개인정보 URL/텍스트) 수정 — PATCH /appInfoLocalizations/{id}. localizationId는 appstore_list_app_info_localizations 결과의 id. 편집 가능 상태(PREPARE_FOR_SUBMISSION / DEVELOPER_REJECTED 등)에서만 반영됨. 제한: name 30자, subtitle 30자.", "execution": { "taskSupport": "forbidden" - "name": "appstore_update_app_info_localization" + "name": "appstore_update_app_info_localization", + "title": "App Store: Update app info localization" }
--- pinned/appstore_update_beta_review_detail +++ observed/appstore_update_beta_review_detail { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Update beta review detail" + }, "description": "TestFlight 베타 심사 정보(연락처·데모 계정·심사 노트)를 채운다 — PATCH /v1/betaAppReviewDetails/{id}. 앱 단위 단일 리소스이며 외부 테스트 심사 제출 전 필수다. 넘긴 필드만 바뀐다. 로그인이 필요한 앱이면 demoAccountRequired=true 와 계정/비밀번호를 반드시 함께 넣는다 — 없으면 반려된다.", "execution": { "taskSupport": "forbidden" - "name": "appstore_update_beta_review_detail" + "name": "appstore_update_beta_review_detail", + "title": "App Store: Update beta review detail" }
--- pinned/appstore_update_beta_test_info +++ observed/appstore_update_beta_test_info { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Update beta test info" + }, "description": "TestFlight 테스트 정보(피드백 이메일·앱 설명 등)를 로케일별로 저장한다 — betaAppLocalizations upsert. 해당 로케일이 있으면 PATCH, 없으면 POST 한다. 외부 테스트에는 feedbackEmail 과 description 이 필요하다.", "execution": { "taskSupport": "forbidden" - "name": "appstore_update_beta_test_info" + "name": "appstore_update_beta_test_info", + "title": "App Store: Update beta test info" }
--- pinned/appstore_update_localization +++ observed/appstore_update_localization { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Update localization" + }, "description": "App Store 버전 로컬라이제이션(메타데이터) 수정 — localizationId 직접 지정. 이 버전의 새로운 기능(whatsNew), 설명(description), 키워드, 프로모션 텍스트를 편집. 수정 가능한 상태(PREPARE_FOR_SUBMISSION 등)인 버전에서만 반영됨", "execution": { "taskSupport": "forbidden" - "name": "appstore_update_localization" + "name": "appstore_update_localization", + "title": "App Store: Update localization" }
--- pinned/appstore_update_product +++ observed/appstore_update_product { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Update product" + }, "description": "App Store IAP 상품의 reference name 변경. productId / 유형은 변경 불가. 스토어에 보이는 표시 이름·설명은 appstore_update_product_localization 을 쓴다.", "execution": { "taskSupport": "forbidden" + "maxLength": 255, + "pattern": "^[A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*$", "type": "string" }, "name": { - "name": "appstore_update_product" + "name": "appstore_update_product", + "title": "App Store: Update product" }
--- pinned/appstore_update_product_localization +++ observed/appstore_update_product_localization { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Update product localization" + }, "description": "App Store IAP/구독 상품의 현지화(표시 이름·설명)를 로케일 단위로 upsert — 있으면 수정, 없으면 생성. 현지화가 비면 상품이 MISSING_METADATA 에서 안 풀려 심사에 넣을 수 없다 (리뷰 노트·스크린샷과는 별개 리소스). locale 은 App Store 표기(ko, en-US, ja, zh-Hant)를 쓴다. 길이 상한은 리소스마다 다르고 Apple 이 강제한다 — 구독은 실측으로 name 35 / description 55 다. 초과하면 Apple 이 \"Max number of characters is (N)\" 으로 실제 상한을 알려주므로 그 값에 맞춰 줄이면 된다. ⚠️ 심사 중인 상품은 현지화가 잠겨 UNMODIFIABLE 로 거부된다 — 결과를 기다리거나 철회 후 수정한다.", "execution": { "taskSupport": "forbidden" - "name": "appstore_update_product_localization" + "name": "appstore_update_product_localization", + "title": "App Store: Update product localization" }
--- pinned/appstore_update_product_review_note +++ observed/appstore_update_product_review_note { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Update product review note" + }, "description": "기존 App Store IAP/구독 상품의 App Review 노트를 수정. appstore_list_products의 productId/type을 사용.", "execution": { "taskSupport": "forbidden" - "name": "appstore_update_product_review_note" + "name": "appstore_update_product_review_note", + "title": "App Store: Update product review note" }
--- pinned/appstore_update_release_type +++ observed/appstore_update_release_type { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Update release type" + }, "description": "이미 만들어진 버전의 출시 방식을 바꾼다 — PATCH /v1/appStoreVersions/{id}. MANUAL(개발자가 직접 출시) / AFTER_APPROVAL(승인되면 자동 출시) / SCHEDULED(지정 시각 출시). SCHEDULED 는 earliestReleaseDate(ISO 8601, 미래 시각)가 함께 필요하다. 편집 가능한 상태에서만 통한다 — 이미 READY_FOR_SALE 이면 바꿀 수 없다. MANUAL 로 만들어 둔 버전을 \"승인되면 알아서 나가게\" 바꾸는 용도가 대부분이다.", "execution": { "taskSupport": "forbidden" - "name": "appstore_update_release_type" + "name": "appstore_update_release_type", + "title": "App Store: Update release type" }
--- pinned/appstore_update_review_notes +++ observed/appstore_update_review_notes { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Update review notes" + }, "description": "App Store 심사 리뷰어 노트(Notes for App Review) 등록/수정. versionId 버전에 appStoreReviewDetail.notes를 PATCH하거나 없으면 POST로 생성. 심사 시 리뷰어에게 전달되는 테스트 계정·기능 안내 텍스트 작성에 사용. 4000자 권장 한도.", "execution": { "taskSupport": "forbidden" - "name": "appstore_update_review_notes" + "name": "appstore_update_review_notes", + "title": "App Store: Update review notes" }
--- pinned/appstore_update_version_string +++ observed/appstore_update_version_string { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Update version string" + }, "description": "기존 App Store 버전 레코드의 versionString 을 변경 (예: 2.0.5 → 2.0.6). ⚠️ 편집 가능한 버전이 이미 있으면 appstore_create_version 이 409 \"cannot create a new version in the current state\" 로 막힌다 — 거절/철회된 버전으로 다음 릴리스를 내보내려면 새로 만들지 말고 이 도구로 **같은 레코드의 이름을 올린다**. 빌드는 CFBundleShortVersionString 이 같은 버전에만 붙으므로, 새 버전의 빌드를 attach 하려면 먼저 이걸 맞춰야 한다. PREPARE_FOR_SUBMISSION / DEVELOPER_REJECTED 등 편집 가능 상태에서만 통한다.", "execution": { "taskSupport": "forbidden" - "name": "appstore_update_version_string" + "name": "appstore_update_version_string", + "title": "App Store: Update version string" }
--- pinned/appstore_update_whats_new +++ observed/appstore_update_whats_new { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Update whats new" + }, "description": "App Store '이 버전의 새로운 기능' 편집 — versionId + locale만 주면 자동으로 로컬라이제이션을 찾아 PATCH. 가장 흔한 사용 케이스. 수정 가능한 상태(PREPARE_FOR_SUBMISSION 등)인 버전에서만 반영됨", "execution": { "taskSupport": "forbidden" - "name": "appstore_update_whats_new" + "name": "appstore_update_whats_new", + "title": "App Store: Update whats new" }
--- pinned/appstore_update_whats_to_test +++ observed/appstore_update_whats_to_test { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Update whats to test" + }, "description": "빌드의 What to Test 를 로케일별로 저장한다 — betaBuildLocalizations upsert. 외부 테스터 배포에는 필수다. 비어 있으면 베타 심사에서 막힌다. 버전 릴리스 노트(appstore_update_whats_new)와는 별개다 — 이건 TestFlight 전용이다.", "execution": { "taskSupport": "forbidden" - "name": "appstore_update_whats_to_test" + "name": "appstore_update_whats_to_test", + "title": "App Store: Update whats to test" }
--- pinned/appstore_upload_preview +++ observed/appstore_upload_preview { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Upload preview" + }, "description": "제품 페이지 미리보기 **동영상**을 업로드한다 — appPreviewSets/appPreviews 4단계 업로드. previewType 세트가 없으면 만들고, 예약 → 조각 업로드 → 커밋까지 한 번에 처리한다. ⚠️ 커밋 후 Apple 인코딩이 남는다 — 성공 응답이 곧 노출 가능은 아니다. appstore_list_previews 로 확인할 것. Apple 제약: 길이 15~30초, previewType 별 해상도 고정, 로케일·타입당 최대 3개. 어기면 인코딩 단계에서 거부된다. previewFrameTimeCode(HH:MM:SS:FF)로 포스터 프레임을 지정할 수 있다. 파일은 절대경로로 넘긴다 (대용량이라 조각 업로드하며, 동영상 바이트는 대화에 싣지 않는다).", "execution": { "taskSupport": "forbidden" - "name": "appstore_upload_preview" + "name": "appstore_upload_preview", + "title": "App Store: Upload preview" }
--- pinned/appstore_upload_product_review_screenshot +++ observed/appstore_upload_product_review_screenshot { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Upload product review screenshot" + }, "description": "기존 App Store IAP/구독 상품의 심사용 스크린샷을 reserve → upload → commit. 상품당 1장, 절대 파일 경로 필요. 이미 있으면 409 \"Screenshot already exists\" — 갈아끼우려면 replace: true (기존 것을 지우고 올린다).", "execution": { "taskSupport": "forbidden" - "name": "appstore_upload_product_review_screenshot" + "name": "appstore_upload_product_review_screenshot", + "title": "App Store: Upload product review screenshot" }
--- pinned/appstore_upload_screenshot +++ observed/appstore_upload_screenshot { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "App Store: Upload screenshot" + }, "description": "App Store 스크린샷 업로드 (자동 4단계: 셋 확보 → 예약 → 청크 업로드 → 커밋). 파일 경로는 로컬 절대경로. displayType은 Apple 공식 enum: APP_IPHONE_69 (6.9\", 1290x2796) / APP_IPHONE_67 (6.7\", 1290x2796) / APP_IPHONE_65 (6.5\", 1242x2688) / APP_IPHONE_61 (6.1\", 1170x2532) / APP_IPHONE_58 (5.8\") / APP_IPHONE_55 (5.5\", 1242x2208) / APP_IPAD_PRO_3GEN_129 (13\", 2064x2752) / APP_IPAD_PRO_3GEN_11 (11\", 1668x2388) / APP_IPAD_PRO_129 (12.9\", 2048x2732) / APP_DESKTOP (2560x1600+). 해상도 틀리면 검수에서 리젝됨. 수정 가능한 버전 상태에서만 반영됨.", "execution": { "taskSupport": "forbidden" - "name": "appstore_upload_screenshot" + "name": "appstore_upload_screenshot", + "title": "App Store: Upload screenshot" }
--- pinned/appstore_verify_credentials +++ observed/appstore_verify_credentials { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "App Store: Verify credentials" + }, "description": "App Store Connect API 키(appstore.json) 유효성 검증 — JWT 서명 + GET /apps 호출로 creds/sign/auth/api 단계별 진단. 첫 도구 호출에서 401로 늦게 터지기 전에 setup 직후 확인용. 매출 리포트 접근 가능 여부도 함께 확인한다 — 그쪽만 요구 롤이 달라서 (Admin/Finance/Sales and Reports) 앱 메타데이터는 다 되는데 매출만 403 인 키가 흔하다. 인자 없음.", "execution": { "taskSupport": "forbidden" - "name": "appstore_verify_credentials" + "name": "appstore_verify_credentials", + "title": "App Store: Verify credentials" }
--- pinned/bigquery_auth_status +++ observed/bigquery_auth_status { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": false, + "readOnlyHint": true, + "title": "BigQuery: Auth status" + }, "description": "현재 BigQuery 인증 상태 조회 — 어떤 인증(서비스 계정/OAuth)이 사용되는지 확인", "execution": { "taskSupport": "forbidden" - "name": "bigquery_auth_status" + "name": "bigquery_auth_status", + "title": "BigQuery: Auth status" }
--- pinned/bigquery_get_table_schema +++ observed/bigquery_get_table_schema { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "BigQuery: Get table schema" + }, "description": "BigQuery 테이블 스키마(컬럼 정보) 조회", "execution": { "taskSupport": "forbidden" - "name": "bigquery_get_table_schema" + "name": "bigquery_get_table_schema", + "title": "BigQuery: Get table schema" }
--- pinned/bigquery_list_datasets +++ observed/bigquery_list_datasets { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "BigQuery: List datasets" + }, "description": "BigQuery 프로젝트의 데이터셋 목록 조회", "execution": { "taskSupport": "forbidden" - "name": "bigquery_list_datasets" + "name": "bigquery_list_datasets", + "title": "BigQuery: List datasets" }
--- pinned/bigquery_list_tables +++ observed/bigquery_list_tables { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "BigQuery: List tables" + }, "description": "BigQuery 데이터셋의 테이블 목록 조회", "execution": { "taskSupport": "forbidden" - "name": "bigquery_list_tables" + "name": "bigquery_list_tables", + "title": "BigQuery: List tables" }
--- pinned/bigquery_run_query +++ observed/bigquery_run_query { - "description": "BigQuery SQL 쿼리 실행 (SELECT). GA4 analytics_* 테이블 분석에 사용. 서비스 계정(권장) 또는 사용자 OAuth 로 인증.", + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "BigQuery: Run query" + }, + "description": "BigQuery 읽기 전용 SQL 쿼리 실행 — 단일 SELECT 문만 허용 (API 호출 전 어휘 검사로 SELECT / WITH / FROM(파이프 문법) 으로 시작하는 단일 문장만 통과시키고, 실행 전 dry run 으로 문장 유형을 다시 확인해 DML/DDL/스크립트는 거부). GA4 analytics_* 테이블 분석에 사용. 30초 안에 안 끝나면 최대 2분 더 기다리고, 그래도 미완료면 jobComplete=false 와 jobId 를 돌려준다. 서비스 계정(권장) 또는 사용자 OAuth 로 인증. ⚠️ \"SELECT 전용\"은 데이터 변경(DML/DDL)이 없다는 뜻일 뿐 부작용이 없다는 뜻이 아니다 — 스캔 바이트만큼 과금되고, SELECT 안에서 원격 함수·ML.GENERATE_TEXT 등 모델 호출·EXTERNAL_QUERY 를 부르면 외부 호출과 추가 비용이 그대로 발생한다.", "execution": { "taskSupport": "forbidden" }, - "description": "실행할 StandardSQL 쿼리", + "description": "실행할 StandardSQL 쿼리 (SELECT / WITH / FROM |> 파이프, 단일 문장)", "type": "string" } }, - "name": "bigquery_run_query" + "name": "bigquery_run_query", + "title": "BigQuery: Run query" }
--- pinned/ci_cancel_build +++ observed/ci_cancel_build { - "description": "진행 중인 빌드를 취소합니다. (GitHub Actions run / GitLab pipeline)", + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "CI: Cancel build" + }, + "description": "진행 중인 빌드를 취소합니다. (GitHub Actions run / GitLab pipeline) ⚠️ 안전 가드: confirm 생략/false 면 아무것도 바꾸지 않고 dry-run preview 만 반환한다. 사용자 명시 승인 후 confirm: true 로 재호출.", "execution": { "taskSupport": "forbidden" }, + "confirm": { + "description": "true 명시 시에만 실제 실행. 생략/false 면 dry-run preview 만 반환 (비가역·공개 사고 차단).", + "type": "boolean" + }, "run_id": { "description": "빌드 ID (ci_trigger_build 또는 ci_list_recent_builds 반환값)", "type": "string" - "name": "ci_cancel_build" + "name": "ci_cancel_build", + "title": "CI: Cancel build" }
--- pinned/ci_get_build_status +++ observed/ci_get_build_status { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "CI: Get build status" + }, "description": "특정 빌드(GitHub Actions run / GitLab pipeline)의 현재 상태를 조회합니다.", "execution": { "taskSupport": "forbidden" - "name": "ci_get_build_status" + "name": "ci_get_build_status", + "title": "CI: Get build status" }
--- pinned/ci_list_recent_builds +++ observed/ci_list_recent_builds { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "CI: List recent builds" + }, "description": "최근 빌드 목록을 조회합니다. 특정 브랜치나 워크플로로 필터링 가능.", "execution": { "taskSupport": "forbidden" - "name": "ci_list_recent_builds" + "name": "ci_list_recent_builds", + "title": "CI: List recent builds" }
--- pinned/ci_list_workflows +++ observed/ci_list_workflows { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "CI: List workflows" + }, "description": "GitHub Actions 워크플로 목록 또는 GitLab 파이프라인 스케줄/트리거 목록을 조회합니다. ci_trigger_build의 workflow 파라미터에 파일명(deploy.yml)을 사용하세요.", "execution": { "taskSupport": "forbidden" - "name": "ci_list_workflows" + "name": "ci_list_workflows", + "title": "CI: List workflows" }
--- pinned/ci_save_config +++ observed/ci_save_config { - "description": "GitHub Actions 또는 GitLab CI 연결 설정을 저장합니다. 저장 위치: ~/.mimi-seed/ci.json (mode 0600). GitHub: provider=\"github\", token=\"ghp_...\" (repo+workflow 스코프 필요) GitHub Enterprise: host=\"https://github.example.com\" 추가 GitLab.com: provider=\"gitlab\", token=\"glpat-...\" Self-hosted GitLab: host=\"https://gitlab.example.com\" 추가", + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": false, + "readOnlyHint": false, + "title": "CI: Save config" + }, + "description": "GitHub Actions 또는 GitLab CI 연결 설정을 저장합니다. 저장 위치: ~/.mimi-seed/ci.json (mode 0600). GitHub: provider=\"github\", token=<GitHub token> (repo+workflow 스코프 필요) GitHub Enterprise: host=\"https://github.example.com\" 추가 GitLab.com: provider=\"gitlab\", token=<GitLab token> Self-hosted GitLab: host=\"https://gitlab.example.com\" 추가", "execution": { "taskSupport": "forbidden" }, - "name": "ci_save_config" + "name": "ci_save_config", + "title": "CI: Save config" }
--- pinned/ci_trigger_build +++ observed/ci_trigger_build { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "CI: Trigger build" + }, "description": "빌드를 트리거합니다. GitHub: workflow 필수 (파일명 \"deploy.yml\" 또는 숫자 ID). workflow_dispatch 트리거가 설정된 워크플로만 실행 가능. GitLab: workflow 불필요 — ref(브랜치)만 지정하면 .gitlab-ci.yml 즉시 실행. 완료 직후 최신 빌드 정보를 반환합니다. run_id를 ci_get_build_status에 사용하세요.", "execution": { "taskSupport": "forbidden" - "name": "ci_trigger_build" + "name": "ci_trigger_build", + "title": "CI: Trigger build" }
--- pinned/facebook_current_config +++ observed/facebook_current_config { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": false, + "readOnlyHint": true, + "title": "Facebook: Current config" + }, "description": "현재 저장된 Facebook 페이지 설정을 확인합니다.", "execution": { "taskSupport": "forbidden" - "name": "facebook_current_config" + "name": "facebook_current_config", + "title": "Facebook: Current config" }
--- pinned/facebook_get_page +++ observed/facebook_get_page { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Facebook: Get page" + }, "description": "Facebook 페이지 정보 조회 + 저장된 토큰 유효성 검증.", "execution": { "taskSupport": "forbidden" - "name": "facebook_get_page" + "name": "facebook_get_page", + "title": "Facebook: Get page" }
--- pinned/facebook_list_pages +++ observed/facebook_list_pages { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Facebook: List pages" + }, "description": "User Access Token으로 접근 가능한 Facebook 페이지 목록을 조회합니다. 페이지별 Page Access Token도 함께 반환.", "execution": { "taskSupport": "forbidden" - "name": "facebook_list_pages" + "name": "facebook_list_pages", + "title": "Facebook: List pages" }
--- pinned/facebook_post_multi_photo +++ observed/facebook_post_multi_photo { - "description": "여러 이미지를 하나의 게시물로 Facebook 페이지에 게시합니다. 2~10장. 모든 이미지는 public URL이어야 합니다. 각 이미지를 unpublished photo로 업로드한 뒤 하나의 feed 게시물로 묶습니다.", + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Facebook: Post multi photo" + }, + "description": "여러 이미지를 하나의 게시물로 Facebook 페이지에 게시합니다. 2~10장. 모든 이미지는 public URL이어야 합니다. 각 이미지를 unpublished photo로 업로드한 뒤 하나의 feed 게시물로 묶습니다. ⚠️ 안전 가드: confirm 생략/false 면 아무것도 바꾸지 않고 dry-run preview 만 반환한다. 사용자 명시 승인 후 confirm: true 로 재호출.", "execution": { "taskSupport": "forbidden" }, + "confirm": { + "description": "true 명시 시에만 실제 실행. 생략/false 면 dry-run preview 만 반환 (비가역·공개 사고 차단).", + "type": "boolean" + }, "imageUrls": { "description": "이미지 URL 배열 (2~10장)", "items": { - "name": "facebook_post_multi_photo" + "name": "facebook_post_multi_photo", + "title": "Facebook: Post multi photo" }
--- pinned/facebook_post_photo +++ observed/facebook_post_photo { - "description": "단일 이미지를 Facebook 페이지에 게시합니다. imageUrl은 public URL이어야 합니다.", + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Facebook: Post photo" + }, + "description": "단일 이미지를 Facebook 페이지에 게시합니다. imageUrl은 public URL이어야 합니다. ⚠️ 안전 가드: confirm 생략/false 면 아무것도 바꾸지 않고 dry-run preview 만 반환한다. 사용자 명시 승인 후 confirm: true 로 재호출.", "execution": { "taskSupport": "forbidden" }, + "confirm": { + "description": "true 명시 시에만 실제 실행. 생략/false 면 dry-run preview 만 반환 (비가역·공개 사고 차단).", + "type": "boolean" + }, "imageUrl": { "description": "이미지의 public URL (HTTPS 권장)", "format": "uri", - "name": "facebook_post_photo" + "name": "facebook_post_photo", + "title": "Facebook: Post photo" }
--- pinned/facebook_save_config +++ observed/facebook_save_config { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Facebook: Save config" + }, "description": "Facebook 페이지 액세스 토큰을 ~/.mimi-seed/facebook.json (mode 0600)에 저장합니다. pageAccessToken: Graph API Explorer 또는 /me/accounts로 발급한 Page Access Token (EAA...). pageId 미입력 시 토큰으로 자동 조회 (/me → id 필드). profile 지정 시 ~/.mimi-seed/social-profiles/<profile>.json에 저장합니다. 저장 직후 페이지 정보를 조회해 토큰 유효성도 자동 검증.", "execution": { "taskSupport": "forbidden" - "name": "facebook_save_config" + "name": "facebook_save_config", + "title": "Facebook: Save config" }
--- pinned/firebase_create_android_app +++ observed/firebase_create_android_app { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Firebase: Create android app" + }, "description": "Firebase에 새 Android 앱 등록", "execution": { "taskSupport": "forbidden" + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" }, "projectId": { - "name": "firebase_create_android_app" + "name": "firebase_create_android_app", + "title": "Firebase: Create android app" }
--- pinned/firebase_create_ios_app +++ observed/firebase_create_ios_app { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Firebase: Create iOS app" + }, "description": "Firebase에 새 iOS 앱 등록", "execution": { "taskSupport": "forbidden" + "maxLength": 255, + "pattern": "^[A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*$", "type": "string" }, "displayName": { - "name": "firebase_create_ios_app" + "name": "firebase_create_ios_app", + "title": "Firebase: Create iOS app" }
--- pinned/firebase_create_project +++ observed/firebase_create_project { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Firebase: Create project" + }, "description": "새 GCP 프로젝트를 만들고 Firebase를 추가한다 (앱 하나당 전용 Firebase 프로젝트 컨벤션 — 기존 프로젝트에 앱만 추가하려면 firebase_create_android_app/firebase_create_ios_app 사용). 두 개의 long-running operation(프로젝트 생성 → Firebase 추가)을 순서대로 완료까지 폴링하므로 최악의 경우 2분 정도 걸릴 수 있다. projectId는 6-30자, 소문자로 시작, 소문자/숫자/하이픈만 가능(끝에 하이픈 금지).", "execution": { "taskSupport": "forbidden" - "name": "firebase_create_project" + "name": "firebase_create_project", + "title": "Firebase: Create project" }
--- pinned/firebase_create_web_app +++ observed/firebase_create_web_app { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Firebase: Create web app" + }, "description": "Firebase에 새 Web 앱 등록", "execution": { "taskSupport": "forbidden" - "name": "firebase_create_web_app" + "name": "firebase_create_web_app", + "title": "Firebase: Create web app" }
--- pinned/firebase_delete_android_app +++ observed/firebase_delete_android_app { - "description": "Firebase Android 앱 삭제", + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Firebase: Delete android app" + }, + "description": "Firebase Android 앱 삭제 ⚠️ 안전 가드: confirm 생략/false 면 아무것도 바꾸지 않고 dry-run preview 만 반환한다. 사용자 명시 승인 후 confirm: true 로 재호출.", "execution": { "taskSupport": "forbidden" }, + "confirm": { + "description": "true 명시 시에만 실제 실행. 생략/false 면 dry-run preview 만 반환 (비가역·공개 사고 차단).", + "type": "boolean" + }, "projectId": { "description": "Firebase 프로젝트 ID", "type": "string" - "name": "firebase_delete_android_app" + "name": "firebase_delete_android_app", + "title": "Firebase: Delete android app" }
--- pinned/firebase_delete_ios_app +++ observed/firebase_delete_ios_app { - "description": "Firebase iOS 앱 삭제", + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Firebase: Delete iOS app" + }, + "description": "Firebase iOS 앱 삭제 ⚠️ 안전 가드: confirm 생략/false 면 아무것도 바꾸지 않고 dry-run preview 만 반환한다. 사용자 명시 승인 후 confirm: true 로 재호출.", "execution": { "taskSupport": "forbidden" }, + "confirm": { + "description": "true 명시 시에만 실제 실행. 생략/false 면 dry-run preview 만 반환 (비가역·공개 사고 차단).", + "type": "boolean" + }, "projectId": { "description": "Firebase 프로젝트 ID", "type": "string" - "name": "firebase_delete_ios_app" + "name": "firebase_delete_ios_app", + "title": "Firebase: Delete iOS app" }
--- pinned/firebase_delete_web_app +++ observed/firebase_delete_web_app { - "description": "Firebase Web 앱 삭제", + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Firebase: Delete web app" + }, + "description": "Firebase Web 앱 삭제 ⚠️ 안전 가드: confirm 생략/false 면 아무것도 바꾸지 않고 dry-run preview 만 반환한다. 사용자 명시 승인 후 confirm: true 로 재호출.", "execution": { "taskSupport": "forbidden" }, + "confirm": { + "description": "true 명시 시에만 실제 실행. 생략/false 면 dry-run preview 만 반환 (비가역·공개 사고 차단).", + "type": "boolean" + }, "projectId": { "description": "Firebase 프로젝트 ID", "type": "string" - "name": "firebase_delete_web_app" + "name": "firebase_delete_web_app", + "title": "Firebase: Delete web app" }
--- pinned/firebase_enable_common_services +++ observed/firebase_enable_common_services { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Firebase: Enable common services" + }, "description": "Firebase 기본 서비스 일괄 활성화 (Firestore, Auth, Storage, FCM 등)", "execution": { "taskSupport": "forbidden" - "name": "firebase_enable_common_services" + "name": "firebase_enable_common_services", + "title": "Firebase: Enable common services" }
--- pinned/firebase_enable_service +++ observed/firebase_enable_service { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Firebase: Enable service" + }, "description": "GCP 서비스 활성화 (예: firestore.googleapis.com)", "execution": { "taskSupport": "forbidden" - "name": "firebase_enable_service" + "name": "firebase_enable_service", + "title": "Firebase: Enable service" }
--- pinned/firebase_get_analytics_details +++ observed/firebase_get_analytics_details { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Firebase: Get analytics details" + }, "description": "프로젝트의 GA4 링크 상세 — 연결된 analyticsProperty + 앱↔data stream 매핑 조회.", "execution": { "taskSupport": "forbidden" - "name": "firebase_get_analytics_details" + "name": "firebase_get_analytics_details", + "title": "Firebase: Get analytics details" }
--- pinned/firebase_get_android_config +++ observed/firebase_get_android_config { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Firebase: Get android config" + }, "description": "google-services.json 다운로드", "execution": { "taskSupport": "forbidden" - "name": "firebase_get_android_config" + "name": "firebase_get_android_config", + "title": "Firebase: Get android config" }
--- pinned/firebase_get_ios_config +++ observed/firebase_get_ios_config { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Firebase: Get iOS config" + }, "description": "GoogleService-Info.plist 다운로드", "execution": { "taskSupport": "forbidden" - "name": "firebase_get_ios_config" + "name": "firebase_get_ios_config", + "title": "Firebase: Get iOS config" }
--- pinned/firebase_get_project +++ observed/firebase_get_project { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Firebase: Get project" + }, "description": "Firebase 프로젝트 상세 정보 조회", "execution": { "taskSupport": "forbidden" - "name": "firebase_get_project" + "name": "firebase_get_project", + "title": "Firebase: Get project" }
+ tool added: firebase_get_remote_config_overview
--- pinned/firebase_get_web_config +++ observed/firebase_get_web_config { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Firebase: Get web config" + }, "description": "Firebase Web 설정 (firebaseConfig 객체) 조회", "execution": { "taskSupport": "forbidden" - "name": "firebase_get_web_config" + "name": "firebase_get_web_config", + "title": "Firebase: Get web config" }
--- pinned/firebase_link_analytics +++ observed/firebase_link_analytics { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Firebase: Link analytics" + }, "description": "Firebase 프로젝트에 Google Analytics(GA4) 링크 → 앱별 measurement 자동 활성화. analyticsAccountId(그 계정에 GA4 property 신규 생성) 또는 analyticsPropertyId(기존 property 링크) 중 하나 필수. 먼저 firebase_enable_common_services 로 firebaseanalytics 활성화 권장. property 이름/web stream 까지 직접 제어하려면 ga4_create_property/ga4_create_data_stream 사용.", "execution": { "taskSupport": "forbidden" - "name": "firebase_link_analytics" + "name": "firebase_link_analytics", + "title": "Firebase: Link analytics" }
--- pinned/firebase_list_android_apps +++ observed/firebase_list_android_apps { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Firebase: List android apps" + }, "description": "Firebase 프로젝트의 Android 앱 목록", "execution": { "taskSupport": "forbidden" - "name": "firebase_list_android_apps" + "name": "firebase_list_android_apps", + "title": "Firebase: List android apps" }
--- pinned/firebase_list_enabled_services +++ observed/firebase_list_enabled_services { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Firebase: List enabled services" + }, "description": "프로젝트에서 활성화된 GCP 서비스 목록", "execution": { "taskSupport": "forbidden" - "name": "firebase_list_enabled_services" + "name": "firebase_list_enabled_services", + "title": "Firebase: List enabled services" }
--- pinned/firebase_list_ios_apps +++ observed/firebase_list_ios_apps { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Firebase: List iOS apps" + }, "description": "Firebase 프로젝트의 iOS 앱 목록", "execution": { "taskSupport": "forbidden" - "name": "firebase_list_ios_apps" + "name": "firebase_list_ios_apps", + "title": "Firebase: List iOS apps" }
--- pinned/firebase_list_projects +++ observed/firebase_list_projects { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Firebase: List projects" + }, "description": "내 Firebase 프로젝트 목록 조회", "execution": { "taskSupport": "forbidden" - "name": "firebase_list_projects" + "name": "firebase_list_projects", + "title": "Firebase: List projects" }
--- pinned/firebase_list_web_apps +++ observed/firebase_list_web_apps { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Firebase: List web apps" + }, "description": "Firebase 프로젝트의 Web 앱 목록", "execution": { "taskSupport": "forbidden" - "name": "firebase_list_web_apps" + "name": "firebase_list_web_apps", + "title": "Firebase: List web apps" }
--- pinned/ga4_create_bigquery_link +++ observed/ga4_create_bigquery_link { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "GA4: Create BigQuery link" + }, "description": "GA4 → BigQuery export 링크 생성. confirm 생략/false 시 읽기 전용 계획만 반환하고, confirm: true 일 때만 계획을 재검사한 뒤 생성한다. 기존 링크가 있으면 no-op.", "execution": { "taskSupport": "forbidden" - "name": "ga4_create_bigquery_link" + "name": "ga4_create_bigquery_link", + "title": "GA4: Create BigQuery link" }
--- pinned/ga4_create_data_stream +++ observed/ga4_create_data_stream { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "GA4: Create data stream" + }, "description": "GA4 property 에 data stream 생성. web → measurementId(G-XXXX) 반환, android/ios → firebaseAppId 반환(Firebase 링크 시). RN 앱은 android/ios 스트림 사용.", "execution": { "taskSupport": "forbidden" + "maxLength": 255, + "pattern": "^[A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*$", "type": "string" }, "defaultUri": { + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" }, "platform": { - "name": "ga4_create_data_stream" + "name": "ga4_create_data_stream", + "title": "GA4: Create data stream" }
--- pinned/ga4_create_property +++ observed/ga4_create_property { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "GA4: Create property" + }, "description": "새 GA4 property 생성. 생성 후 ga4_create_data_stream 으로 플랫폼별 stream(웹=measurement ID, 앱=firebaseAppId)을 붙인다.", "execution": { "taskSupport": "forbidden" - "name": "ga4_create_property" + "name": "ga4_create_property", + "title": "GA4: Create property" }
--- pinned/ga4_list_account_summaries +++ observed/ga4_list_account_summaries { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "GA4: List account summaries" + }, "description": "접근 가능한 Google Analytics 계정 + 각 계정의 GA4 property 요약. accountId / propertyId 를 확인할 때 먼저 호출. analytics.edit 스코프 필요(없으면 재로그인 안내).", "execution": { "taskSupport": "forbidden" - "name": "ga4_list_account_summaries" + "name": "ga4_list_account_summaries", + "title": "GA4: List account summaries" }
--- pinned/ga4_list_data_streams +++ observed/ga4_list_data_streams { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "GA4: List data streams" + }, "description": "GA4 property 의 data stream 목록 (measurementId / firebaseAppId 평탄화).", "execution": { "taskSupport": "forbidden" - "name": "ga4_list_data_streams" + "name": "ga4_list_data_streams", + "title": "GA4: List data streams" }
--- pinned/ga4_list_properties +++ observed/ga4_list_properties { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "GA4: List properties" + }, "description": "특정 GA 계정 하위 GA4 property 목록.", "execution": { "taskSupport": "forbidden" - "name": "ga4_list_properties" + "name": "ga4_list_properties", + "title": "GA4: List properties" }
--- pinned/ga4_plan_bigquery_link +++ observed/ga4_plan_bigquery_link { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "GA4: Plan BigQuery link" + }, "description": "GA4 → BigQuery export 링크 생성 계획을 읽기 전용으로 점검. 기존 링크, 대상 프로젝트, 데이터셋 위치와 export 옵션을 반환하며 원격 상태를 변경하지 않는다.", "execution": { "taskSupport": "forbidden" - "name": "ga4_plan_bigquery_link" + "name": "ga4_plan_bigquery_link", + "title": "GA4: Plan BigQuery link" }
--- pinned/ga4_run_report +++ observed/ga4_run_report { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "GA4: Run report" + }, "description": "GA4 Data API 리포트 (활성 사용자·이벤트 등). dimensions/metrics 는 쉼표 구분 GA4 API 이름.", "execution": { "taskSupport": "forbidden" - "name": "ga4_run_report" + "name": "ga4_run_report", + "title": "GA4: Run report" }
--- pinned/gcp_create_budget +++ observed/gcp_create_budget { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "GCP: Create budget" + }, "description": "예산 + 알림 임계 생성. ⚠️ **예산은 알림만 한다. 지출을 막지 않는다.** 하드 차단은 Pub/Sub→결제해제 함수뿐이고 그건 앱을 죽인다. 실질 방어는 각 서비스의 상한(예: Cloud Functions maxInstances)이고 예산은 트립와이어다. ⚠️ GCP 에 **일 예산은 없다** — 기간은 월(기본)/분기/연/사용자지정뿐. \"하루 N원\"을 원하면 월 환산하거나, 실사용이 적을 때는 작은 월 예산을 알람으로 쓰는 게 더 빨리 잡힌다. projectIds 를 반드시 고려할 것 — 공용 결제 계정에서 생략하면 알림이 소음이 된다(gcp_list_billing_projects 로 먼저 확인). 권한은 결제 계정 레벨 IAM 이라 서비스 계정 키로는 대개 403 — 사용자 OAuth 로 호출된다.", "execution": { "taskSupport": "forbidden" - "name": "gcp_create_budget" + "name": "gcp_create_budget", + "title": "GCP: Create budget" }
--- pinned/gcp_get_billing_info +++ observed/gcp_get_billing_info { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "GCP: Get billing info" + }, "description": "프로젝트의 결제 상태 조회 — Blaze(결제 계정 연결) 여부와 연결된 결제 계정 ID. Cloud Functions/Run 배포 전 필수 확인. ⚠️ Cloud Billing API 가 꺼져 있으면 403 이 난다 — 그건 \"Spark 이라서\"가 아니라 조회 자체가 막힌 것이다. 그 경우 firebase_enable_service(projectId, \"cloudbilling.googleapis.com\") 로 먼저 켠 뒤 다시 호출.", "execution": { "taskSupport": "forbidden" - "name": "gcp_get_billing_info" + "name": "gcp_get_billing_info", + "title": "GCP: Get billing info" }
--- pinned/gcp_list_billing_projects +++ observed/gcp_list_billing_projects { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "GCP: List billing projects" + }, "description": "결제 계정에 붙은 프로젝트 목록 = **비용 범위 확인**. 프로젝트가 2개 이상이면(shared=true) 그 계정은 공용이므로 **계정 전체 예산은 쓰지 말 것** — 기존 지출만으로 임계를 즉시 넘겨 알림이 소음이 된다. gcp_create_budget 에 projectIds 를 넘겨 범위를 좁힌다.", "execution": { "taskSupport": "forbidden" - "name": "gcp_list_billing_projects" + "name": "gcp_list_billing_projects", + "title": "GCP: List billing projects" }
--- pinned/gcp_list_budgets +++ observed/gcp_list_budgets { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "GCP: List budgets" + }, "description": "결제 계정의 예산 목록 (금액·프로젝트 필터·알림 임계). 중복 생성 전 확인용.", "execution": { "taskSupport": "forbidden" - "name": "gcp_list_budgets" + "name": "gcp_list_budgets", + "title": "GCP: List budgets" }
--- pinned/generate_release_notes_from_commits +++ observed/generate_release_notes_from_commits { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Generate release notes from commits" + }, "description": "git 커밋 내역을 받아 Claude AI로 앱 스토어용 릴리즈 노트를 생성합니다. 3가지 톤(간결/상세/마케팅)과 다국어 버전을 동시에 생성합니다. ANTHROPIC_API_KEY 환경변수가 필요합니다. commits: [{ message, author?, date? }] 형태로 전달하세요. locales: 다국어 생성할 로케일 배열 (예: [\"ko\", \"en-US\", \"ja\"]) 생성 후 playstore_update_release_notes 또는 appstore_update_whats_new로 적용하세요.", "execution": { "taskSupport": "forbidden" - "name": "generate_release_notes_from_commits" + "name": "generate_release_notes_from_commits", + "title": "Generate release notes from commits" }
--- pinned/generate_review_reply +++ observed/generate_review_reply { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Generate review reply" + }, "description": "Play Store / App Store 리뷰에 대한 AI 답변 초안을 생성합니다. ANTHROPIC_API_KEY 환경변수가 필요합니다. tone: friendly(친근) / professional(정중) / empathetic(공감) / brief(간결) — 기본: friendly language: ko / en / ja / zh 등 — 기본: ko ⚠ 생성된 답변은 초안입니다. 게시 전 반드시 검토하세요. 답변 게시는 playstore_reply_review 도구를 사용하세요.", "execution": { "taskSupport": "forbidden" - "name": "generate_review_reply" + "name": "generate_review_reply", + "title": "Generate review reply" }
--- pinned/googleads_config_status +++ observed/googleads_config_status { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": false, + "readOnlyHint": true, + "title": "Google Ads: Config status" + }, "description": "Google Ads 연동 설정 현황 확인", "execution": { "taskSupport": "forbidden" - "name": "googleads_config_status" + "name": "googleads_config_status", + "title": "Google Ads: Config status" }
--- pinned/googleads_get_campaign_report +++ observed/googleads_get_campaign_report { - "description": "기간별 캠페인 성과 리포트 (클릭, 노출, 비용, 전환수, CPI, CTR)", + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Google Ads: Get campaign report" + }, + "description": "기간별 캠페인 성과 리포트 (클릭, 노출, 계정 통화 비용, 전환수, 전환당 비용). 설치 CPI나 코호트 ROAS가 아님.", "execution": { "taskSupport": "forbidden" }, - "name": "googleads_get_campaign_report" + "name": "googleads_get_campaign_report", + "title": "Google Ads: Get campaign report" }
--- pinned/googleads_get_uac_report +++ observed/googleads_get_uac_report { - "description": "앱 캠페인(UAC) 리포트 — 앱 설치 캠페인별 설치수, CPI, ROAS 집계", + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Google Ads: Get UAC report" + }, + "description": "앱 캠페인(UAC) 비용·전환 리포트. legacy installs/cpi 필드는 일반 전환 기반 별칭이며 설치수·설치 CPI·D7 ROAS로 단정하지 말 것.", "execution": { "taskSupport": "forbidden" }, - "name": "googleads_get_uac_report" + "name": "googleads_get_uac_report", + "title": "Google Ads: Get UAC report" }
--- pinned/googleads_list_accessible_customers +++ observed/googleads_list_accessible_customers { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Google Ads: List accessible customers" + }, "description": "OAuth 토큰으로 접근 가능한 Google Ads 계정 목록 (API 연결 확인용)", "execution": { "taskSupport": "forbidden" - "name": "googleads_list_accessible_customers" + "name": "googleads_list_accessible_customers", + "title": "Google Ads: List accessible customers" }
--- pinned/googleads_list_campaigns +++ observed/googleads_list_campaigns { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Google Ads: List campaigns" + }, "description": "Google Ads 캠페인 목록 조회 (상태, 채널 타입, 일일 예산 포함)", "execution": { "taskSupport": "forbidden" - "name": "googleads_list_campaigns" + "name": "googleads_list_campaigns", + "title": "Google Ads: List campaigns" }
--- pinned/googleads_save_config +++ observed/googleads_save_config { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": false, + "readOnlyHint": false, + "title": "Google Ads: Save config" + }, "description": "Google Ads API 설정 저장 (Developer Token + 계정 ID). 최초 1회만 필요.", "execution": { "taskSupport": "forbidden" - "name": "googleads_save_config" + "name": "googleads_save_config", + "title": "Google Ads: Save config" }
--- pinned/gsc_get_sitemap +++ observed/gsc_get_sitemap { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Search Console: Get sitemap" + }, "description": "특정 사이트맵 1개의 상세(타입별 submitted/indexed, 경고/오류, 처리 시각) 조회.", "execution": { "taskSupport": "forbidden" - "name": "gsc_get_sitemap" + "name": "gsc_get_sitemap", + "title": "Search Console: Get sitemap" }
--- pinned/gsc_inspect_url +++ observed/gsc_inspect_url { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Search Console: Inspect URL" + }, "description": "URL 1개의 실제 색인 상태 검사 (coverageState, robots.txt 허용 여부, 마지막 크롤 시각, 정규 URL, 리치 결과). 사이트맵 리포트보다 정확한 색인 진단의 단일 출처.", "execution": { "taskSupport": "forbidden" - "name": "gsc_inspect_url" + "name": "gsc_inspect_url", + "title": "Search Console: Inspect URL" }
--- pinned/gsc_list_sitemaps +++ observed/gsc_list_sitemaps { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Search Console: List sitemaps" + }, "description": "속성에 제출된 사이트맵 목록 (마지막 다운로드 시각, 경고/오류 수, submitted/indexed 카운트). ⚠️ 사이트맵 리포트의 indexed 수치는 신뢰도 낮음 — 실제 색인 여부는 gsc_inspect_url 로 확인.", "execution": { "taskSupport": "forbidden" - "name": "gsc_list_sitemaps" + "name": "gsc_list_sitemaps", + "title": "Search Console: List sitemaps" }
--- pinned/gsc_list_sites +++ observed/gsc_list_sites { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Search Console: List sites" + }, "description": "Search Console에 등록된(권한 있는) 속성 목록 + 권한 레벨 조회. siteUrl 값을 확인할 때 먼저 호출.", "execution": { "taskSupport": "forbidden" - "name": "gsc_list_sites" + "name": "gsc_list_sites", + "title": "Search Console: List sites" }
--- pinned/gsc_search_analytics +++ observed/gsc_search_analytics { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Search Console: Search analytics" + }, "description": "검색 성과 데이터 조회 (클릭·노출·CTR·평균순위). dimensions로 query/page/country/device/date/searchAppearance 별 분해. 요약(가중 평균순위 포함) + rows 반환.", "execution": { "taskSupport": "forbidden" - "name": "gsc_search_analytics" + "name": "gsc_search_analytics", + "title": "Search Console: Search analytics" }
--- pinned/gsc_submit_sitemap +++ observed/gsc_submit_sitemap { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Search Console: Submit sitemap" + }, "description": "사이트맵을 Search Console에 제출(또는 재제출)해 재크롤을 유도. webmasters read-write 스코프 필요.", "execution": { "taskSupport": "forbidden" - "name": "gsc_submit_sitemap" + "name": "gsc_submit_sitemap", + "title": "Search Console: Submit sitemap" }
--- pinned/iam_add_iam_policy_binding +++ observed/iam_add_iam_policy_binding { - "description": "프로젝트 IAM 정책에 (member → role) 바인딩 추가. 이미 같은 조합이 있으면 no-op. member 형식: `serviceAccount:<email>` / `user:<email>` / `group:<email>`. 주의: 이건 Google Cloud IAM 역할입니다. Play Console의 \"View financial data\" 권한은 별도 — Play Console → Users and permissions에서 부여.", + "annotations": { + "destructiveHint": true, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Cloud IAM: Add IAM policy binding" + }, + "description": "프로젝트 IAM 정책에 (member → role) 바인딩 추가. 이미 같은 조합이 있으면 no-op. member 형식: `serviceAccount:<email>` / `user:<email>` / `group:<email>`. 주의: 이건 Google Cloud IAM 역할입니다. Play Console의 \"View financial data\" 권한은 별도 — Play Console → Users and permissions에서 부여. ⚠️ 안전 가드: confirm 생략/false 면 아무것도 바꾸지 않고 dry-run preview 만 반환한다. 사용자 명시 승인 후 confirm: true 로 재호출.", "execution": { "taskSupport": "forbidden" }, + "confirm": { + "description": "true 명시 시에만 실제 실행. 생략/false 면 dry-run preview 만 반환 (비가역·공개 사고 차단).", + "type": "boolean" + }, "member": { "description": "권한 받을 주체 (예: serviceAccount:my-sa@my-project.iam.gserviceaccount.com)", "type": "string" - "name": "iam_add_iam_policy_binding" + "name": "iam_add_iam_policy_binding", + "title": "Cloud IAM: Add IAM policy binding" }
--- pinned/iam_create_key +++ observed/iam_create_key { - "description": "주어진 서비스 계정의 새 JSON 키를 발급. 응답에 전체 JSON 포함 — 그대로 onesub의 GOOGLE_SERVICE_ACCOUNT_KEY 환경변수로 쓸 수 있음. 주의: 반환된 JSON은 영구 자격증명이므로 안전하게 보관. 한 서비스 계정당 키 최대 10개 (기존 키 회수 후 발급 필요하면 iam_list_keys로 먼저 확인).", + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Cloud IAM: Create key" + }, + "description": "주어진 서비스 계정의 새 JSON 키를 발급해 ~/.mimi-seed/keys/<계정>-<keyId>.json (0600) 에 저장하고 경로만 반환. 개인키는 응답에 포함되지 않음 — 다음 단계는 경로를 넘긴다: playstore_register_service_account(serviceAccountJsonPath=…) / playstore_verify_service_account(serviceAccountJsonPath=…) / jenkins_upload_playstore_sa(service_account_json_path=…). 한 서비스 계정당 키 최대 10개 (기존 키 회수 후 발급 필요하면 iam_list_keys로 먼저 확인). ⚠️ 안전 가드: confirm 생략/false 면 아무것도 바꾸지 않고 dry-run preview 만 반환한다. 사용자 명시 승인 후 confirm: true 로 재호출.", "execution": { "taskSupport": "forbidden" }, + "confirm": { + "description": "true 명시 시에만 실제 실행. 생략/false 면 dry-run preview 만 반환 (비가역·공개 사고 차단).", + "type": "boolean" + }, "serviceAccount": { "description": "서비스 계정 이메일", "type": "string" - "name": "iam_create_key" + "name": "iam_create_key", + "title": "Cloud IAM: Create key" }
--- pinned/iam_create_service_account +++ observed/iam_create_service_account { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Cloud IAM: Create service account" + }, "description": "새 서비스 계정 생성. accountId는 이메일의 로컬 파트 (예: \"onesub-play-verifier\" → onesub-play-verifier@<project>.iam.gserviceaccount.com).", "execution": { "taskSupport": "forbidden" - "name": "iam_create_service_account" + "name": "iam_create_service_account", + "title": "Cloud IAM: Create service account" }
--- pinned/iam_list_keys +++ observed/iam_list_keys { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Cloud IAM: List keys" + }, "description": "주어진 서비스 계정의 기존 키 목록. keyId / keyType / 만료시간 반환. 회수할 키 찾을 때 사용.", "execution": { "taskSupport": "forbidden" - "name": "iam_list_keys" + "name": "iam_list_keys", + "title": "Cloud IAM: List keys" }
--- pinned/iam_list_service_accounts +++ observed/iam_list_service_accounts { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Cloud IAM: List service accounts" + }, "description": "주어진 projectId의 서비스 계정 목록. 이메일 / displayName / disabled 상태 반환.", "execution": { "taskSupport": "forbidden" - "name": "iam_list_service_accounts" + "name": "iam_list_service_accounts", + "title": "Cloud IAM: List service accounts" }
--- pinned/instagram_get_account +++ observed/instagram_get_account { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Instagram: Get account" + }, "description": "Instagram 계정 정보 조회 + 저장된 토큰 유효성 검증.", "execution": { "taskSupport": "forbidden" - "name": "instagram_get_account" + "name": "instagram_get_account", + "title": "Instagram: Get account" }
--- pinned/instagram_post_carousel +++ observed/instagram_post_carousel { - "description": "여러 이미지를 캐러셀(swipe)로 게시합니다. 2~10장. 모든 이미지는 public URL이어야 함. 3-step API: 각 이미지 children container → carousel container → publish. 일부 이미지에서 실패하면 전체 실패 (이미 만든 children container는 자동 삭제 안 됨 — Instagram이 알아서 처리).", + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Instagram: Post carousel" + }, + "description": "여러 이미지를 캐러셀(swipe)로 게시합니다. 2~10장. 모든 이미지는 public URL이어야 함. 3-step API: 각 이미지 children container → carousel container → publish. 일부 이미지에서 실패하면 전체 실패 (이미 만든 children container는 자동 삭제 안 됨 — Instagram이 알아서 처리). ⚠️ 안전 가드: confirm 생략/false 면 아무것도 바꾸지 않고 dry-run preview 만 반환한다. 사용자 명시 승인 후 confirm: true 로 재호출.", "execution": { "taskSupport": "forbidden" }, + "confirm": { + "description": "true 명시 시에만 실제 실행. 생략/false 면 dry-run preview 만 반환 (비가역·공개 사고 차단).", + "type": "boolean" + }, "imageUrls": { "description": "이미지 URL 배열 (2~10장)", "items": { - "name": "instagram_post_carousel" + "name": "instagram_post_carousel", + "title": "Instagram: Post carousel" }
--- pinned/instagram_post_image +++ observed/instagram_post_image { - "description": "단일 이미지를 Instagram에 게시합니다. imageUrl은 public URL이어야 합니다 (Graph API 제약). 로컬 파일은 미리 S3/R2/Cloudinary 등에 업로드 필요. 캡션에는 해시태그(#)와 멘션(@) 포함 가능. 줄바꿈 \\n 사용. 2-step API: container 생성 → media_publish.", + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Instagram: Post image" + }, + "description": "단일 이미지를 Instagram에 게시합니다. imageUrl은 public URL이어야 합니다 (Graph API 제약). 로컬 파일은 미리 S3/R2/Cloudinary 등에 업로드 필요. 캡션에는 해시태그(#)와 멘션(@) 포함 가능. 줄바꿈 \\n 사용. 2-step API: container 생성 → media_publish. ⚠️ 안전 가드: confirm 생략/false 면 아무것도 바꾸지 않고 dry-run preview 만 반환한다. 사용자 명시 승인 후 confirm: true 로 재호출.", "execution": { "taskSupport": "forbidden" }, + "confirm": { + "description": "true 명시 시에만 실제 실행. 생략/false 면 dry-run preview 만 반환 (비가역·공개 사고 차단).", + "type": "boolean" + }, "imageUrl": { "description": "이미지의 public URL (HTTPS 권장)", "format": "uri", - "name": "instagram_post_image" + "name": "instagram_post_image", + "title": "Instagram: Post image" }
--- pinned/instagram_save_config +++ observed/instagram_save_config { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Instagram: Save config" + }, "description": "Instagram 토큰을 ~/.mimi-seed/instagram.json (mode 0600)에 저장합니다. accessToken은 두 형식 모두 자동 감지: IGAA... = Instagram API with Instagram Login (Meta 신규, FB Page 불필요) EAA... = Instagram Graph API via Facebook Login (FB Page+IG Business 연결 필요) userId 미입력 시 토큰으로 자동 조회 (/me 또는 /me/accounts). profile 지정 시 ~/.mimi-seed/social-profiles/<profile>.json에 저장합니다. 저장 직후 토큰 유효성도 자동 검증.", "execution": { "taskSupport": "forbidden" - "name": "instagram_save_config" + "name": "instagram_save_config", + "title": "Instagram: Save config" }
--- pinned/jenkins_create_credential +++ observed/jenkins_create_credential { - "description": "Jenkins에 Secret Text credential을 생성하거나 업데이트합니다. 비밀번호, API 키, 앱 시크릿 등 문자열 값에 사용하세요. 같은 id가 이미 존재하면 자동으로 업데이트합니다. 설정이 없으면 jenkins_status를 먼저 호출하세요.", + "annotations": { + "destructiveHint": true, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Jenkins: Create credential" + }, + "description": "Jenkins에 Secret Text credential을 생성하거나 업데이트합니다. 비밀번호, API 키, 앱 시크릿 등 문자열 값에 사용하세요. 새 id 는 바로 생성한다. 같은 id 가 이미 있으면 기존 값을 되돌릴 수 없게 덮어쓰므로 confirm 생략/false 면 아무것도 바꾸지 않고 \"이미 존재\" dry-run 만 반환 — 사용자 승인 후 confirm: true 로 재호출. 설정이 없으면 jenkins_status를 먼저 호출하세요.", "execution": { "taskSupport": "forbidden" }, + "confirm": { + "description": "같은 id 가 이미 있을 때만 필요. true 면 기존 값을 교체", + "type": "boolean" + }, "description": { "description": "설명 (선택)", "type": "string" - "description": "저장할 비밀값", + "description": "저장할 비밀값. secret_file 과 둘 중 하나", "type": "string" + }, + "secret_field": { + "description": "secret_file 에서 꺼낼 필드 (storePassword / keyPassword / keyAlias)", + "enum": [ + "storePassword", + "keyPassword", + "keyAlias" + ], + "type": "string" + }, + "secret_file": { + "description": "권장 — android_generate_keystore 가 만든 signing.json 절대경로 (~/.mimi-seed/keystores/ 안만 허용). 비밀값이 대화에 남지 않음", + "type": "string" } }, "required": [ - "id", - "secret" + "id" ], "type": "object" }, - "name": "jenkins_create_credential" + "name": "jenkins_create_credential", + "title": "Jenkins: Create credential" }
--- pinned/jenkins_create_job +++ observed/jenkins_create_job { - "description": "config.xml 로 새 Jenkins 잡을 생성합니다 (createItem). 같은 이름의 잡이 이미 있으면 실패합니다. 덮어쓰려면 overwrite=true 를 주거나 jenkins_update_job 을 쓰세요. 폴더 안에 만들려면 job 에 \"folder/name\" 을 넘깁니다 (폴더는 미리 존재해야 합니다). config_xml 은 Pipeline job 이면 flow-definition 루트 엘리먼트를 갖는 XML 전문입니다.", + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Jenkins: Create job" + }, + "description": "config.xml 로 새 Jenkins 잡을 생성합니다 (createItem). 같은 이름의 잡이 이미 있으면 실패합니다. 덮어쓰려면 overwrite=true 를 주거나 jenkins_update_job 을 쓰세요. 폴더 안에 만들려면 job 에 \"folder/name\" 을 넘깁니다 (폴더는 미리 존재해야 합니다). config_xml 은 Pipeline job 이면 flow-definition 루트 엘리먼트를 갖는 XML 전문입니다. ⚠️ 안전 가드: confirm 생략/false 면 아무것도 바꾸지 않고 dry-run preview 만 반환한다. 사용자 명시 승인 후 confirm: true 로 재호출.", "execution": { "taskSupport": "forbidden" }, + "confirm": { + "description": "true 명시 시에만 실제 실행. 생략/false 면 dry-run preview 만 반환 (비가역·공개 사고 차단).", + "type": "boolean" + }, "job": { "description": "잡 경로 (예: my-app, team-folder/my-app)", "type": "string" - "name": "jenkins_create_job" + "name": "jenkins_create_job", + "title": "Jenkins: Create job" }
--- pinned/jenkins_delete_credential +++ observed/jenkins_delete_credential { - "description": "Jenkins credential을 삭제합니다. 비가역 작업입니다. 설정이 없으면 jenkins_status를 먼저 호출하세요.", + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Jenkins: Delete credential" + }, + "description": "Jenkins credential을 삭제합니다. 비가역 작업입니다. 설정이 없으면 jenkins_status를 먼저 호출하세요. ⚠️ 안전 가드: confirm 생략/false 면 아무것도 바꾸지 않고 dry-run preview 만 반환한다. 사용자 명시 승인 후 confirm: true 로 재호출.", "execution": { "taskSupport": "forbidden" }, + "confirm": { + "description": "true 명시 시에만 실제 실행. 생략/false 면 dry-run preview 만 반환 (비가역·공개 사고 차단).", + "type": "boolean" + }, "id": { "description": "삭제할 Credential ID", "type": "string" - "name": "jenkins_delete_credential" + "name": "jenkins_delete_credential", + "title": "Jenkins: Delete credential" }
+ tool added: jenkins_get_build_status
--- pinned/jenkins_get_job_config +++ observed/jenkins_get_job_config { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Jenkins: Get job config" + }, "description": "잡의 config.xml 원문을 가져옵니다. 잡을 수정하기 전에 현재 설정을 확인하거나 백업할 때 사용하세요. 폴더 안의 잡은 \"folder/job\" 형태로 경로를 넘깁니다.", "execution": { "taskSupport": "forbidden" - "name": "jenkins_get_job_config" + "name": "jenkins_get_job_config", + "title": "Jenkins: Get job config" }
+ tool added: jenkins_get_queue_item
--- pinned/jenkins_list_credentials +++ observed/jenkins_list_credentials { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Jenkins: List credentials" + }, "description": "Jenkins에 등록된 credential 목록을 조회합니다 (id / displayName / type). 설정이 없으면 jenkins_status를 먼저 호출해 연결 정보를 확인하세요.", "execution": { "taskSupport": "forbidden" - "name": "jenkins_list_credentials" + "name": "jenkins_list_credentials", + "title": "Jenkins: List credentials" }
--- pinned/jenkins_list_jobs +++ observed/jenkins_list_jobs { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Jenkins: List jobs" + }, "description": "Jenkins 잡 목록을 조회합니다 (이름 / URL / 상태색). folder를 주면 그 폴더 안만 조회합니다. 재귀하지 않고 한 단계만 봅니다. 설정이 없으면 jenkins_status를 먼저 호출하세요.", "execution": { "taskSupport": "forbidden" - "name": "jenkins_list_jobs" + "name": "jenkins_list_jobs", + "title": "Jenkins: List jobs" }
--- pinned/jenkins_save_config +++ observed/jenkins_save_config { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Jenkins: Save config" + }, "description": "Jenkins 서버 연결 설정을 저장합니다 (~/.mimi-seed/jenkins.json, mode 0600). 이 도구를 호출하기 전에 사용자에게 URL / username / token을 먼저 확인하세요. 로컬 Jenkins가 없어도 회사·원격 서버의 URL을 그대로 사용할 수 있습니다. API Token 발급: Jenkins 대시보드 → [사용자 이름] → 설정 → API Token → \"Add new Token\". 저장 후 jenkins_list_credentials 로 연결을 검증하세요.", "execution": { "taskSupport": "forbidden" - "name": "jenkins_save_config" + "name": "jenkins_save_config", + "title": "Jenkins: Save config" }
--- pinned/jenkins_status +++ observed/jenkins_status { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Jenkins: Status" + }, "description": "⭐ Jenkins 관련 작업을 시작하기 전에 반드시 이 도구를 먼저 호출하세요. 현재 Jenkins 연결 설정(~/.mimi-seed/jenkins.json) 유무를 확인합니다. 설정이 없으면 사용자에게 Jenkins URL / 사용자 ID / API Token을 물어본 뒤 jenkins_save_config를 호출해 저장하세요. API Token 발급: Jenkins 대시보드 → [사용자 이름] → 설정 → API Token → \"Add new Token\". 로컬 Jenkins 없이 회사·외부 서버도 URL만 맞으면 연결 가능합니다.", "execution": { "taskSupport": "forbidden" - "name": "jenkins_status" + "name": "jenkins_status", + "title": "Jenkins: Status" }
+ tool added: jenkins_trigger_build
--- pinned/jenkins_update_job +++ observed/jenkins_update_job { - "description": "기존 Jenkins 잡의 config.xml 을 통째로 교체합니다. 잡이 없으면 실패합니다 (생성은 jenkins_create_job). 기존 설정이 사라지므로 jenkins_get_job_config 로 먼저 백업하는 것을 권장합니다.", + "annotations": { + "destructiveHint": true, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Jenkins: Update job" + }, + "description": "기존 Jenkins 잡의 config.xml 을 통째로 교체합니다. 잡이 없으면 실패합니다 (생성은 jenkins_create_job). 기존 설정이 사라지므로 jenkins_get_job_config 로 먼저 백업하는 것을 권장합니다. ⚠️ 안전 가드: confirm 생략/false 면 아무것도 바꾸지 않고 dry-run preview 만 반환한다. 사용자 명시 승인 후 confirm: true 로 재호출.", "execution": { "taskSupport": "forbidden" }, + "confirm": { + "description": "true 명시 시에만 실제 실행. 생략/false 면 dry-run preview 만 반환 (비가역·공개 사고 차단).", + "type": "boolean" + }, "job": { "description": "잡 경로 (예: my-app, team-folder/my-app)", "type": "string" - "name": "jenkins_update_job" + "name": "jenkins_update_job", + "title": "Jenkins: Update job" }
--- pinned/jenkins_upload_keystore +++ observed/jenkins_upload_keystore { - "description": "Jenkins에 Android keystore 파일을 Secret File credential로 업로드합니다. keystore_base64에 .jks/.p12 파일을 base64로 인코딩한 값을 전달하세요. 같은 id가 이미 존재하면 자동으로 교체합니다. 설정이 없으면 jenkins_status를 먼저 호출하세요.", + "annotations": { + "destructiveHint": true, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Jenkins: Upload keystore" + }, + "description": "Jenkins에 Android keystore 파일을 Secret File credential로 업로드합니다. keystore_base64에 .jks/.p12 파일을 base64로 인코딩한 값을 전달하세요. 새 id 는 바로 생성한다. 같은 id 가 이미 있으면 기존 keystore 를 되돌릴 수 없게 교체하므로 confirm 생략/false 면 아무것도 바꾸지 않고 \"이미 존재\" dry-run 만 반환 — 사용자 승인 후 confirm: true 로 재호출. 설정이 없으면 jenkins_status를 먼저 호출하세요.", "execution": { "taskSupport": "forbidden" }, + "confirm": { + "description": "같은 id 가 이미 있을 때만 필요. true 면 기존 keystore 를 교체", + "type": "boolean" + }, "description": { "description": "설명 (선택)", "type": "string" - "description": "keystore 파일 내용을 base64로 인코딩한 값", + "description": "keystore 파일 내용을 base64로 인코딩한 값. keystore_path 와 둘 중 하나", "type": "string" + }, + "keystore_path": { + "description": "권장 — android_generate_keystore 가 만든 keystore 절대경로 (~/.mimi-seed/keystores/ 안만 허용)", + "type": "string" } }, "required": [ - "id", - "keystore_base64" + "id" ], "type": "object" }, - "name": "jenkins_upload_keystore" + "name": "jenkins_upload_keystore", + "title": "Jenkins: Upload keystore" }
--- pinned/jenkins_upload_playstore_sa +++ observed/jenkins_upload_playstore_sa { - "description": "setup_playstore_connection으로 생성한 Play Store 서비스 계정 JSON을 Jenkins Secret File credential로 업로드합니다. ~/.mimi-seed/play-service-accounts/{package_name}.json 을 읽어 base64로 변환 후 등록합니다. setup_playstore_connection 실행 후 반드시 이 도구를 호출하세요.", + "annotations": { + "destructiveHint": true, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Jenkins: Upload Play Store SA" + }, + "description": "setup_playstore_connection으로 생성한 Play Store 서비스 계정 JSON을 Jenkins Secret File credential로 업로드합니다. ~/.mimi-seed/play-service-accounts/{package_name}.json 을 읽어 base64로 변환 후 등록합니다. iam_create_key 로 막 발급한 키를 올리려면 service_account_json_path 에 그 경로(~/.mimi-seed/keys/ 안)를 넘기세요. setup_playstore_connection 실행 후 반드시 이 도구를 호출하세요. 새 id 는 바로 생성한다. 같은 id 가 이미 있으면 기존 SA JSON 을 되돌릴 수 없게 교체하므로 confirm 생략/false 면 아무것도 바꾸지 않고 \"이미 존재\" dry-run 만 반환 — 사용자 승인 후 confirm: true 로 재호출.", "execution": { "taskSupport": "forbidden" }, + "confirm": { + "description": "같은 id 가 이미 있을 때만 필요. true 면 기존 SA JSON 을 교체", + "type": "boolean" + }, "credential_id": { "description": "Jenkins Credential ID (생략 시 \"<앱>-playstore-sa\")", "type": "string" + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" + }, + "service_account_json_path": { + "description": "선택 — iam_create_key 가 저장한 키 파일 절대경로 (~/.mimi-seed/keys/ 안만 허용). 생략하면 패키지별 등록 SA 사용", + "type": "string" } }, "required": [ - "name": "jenkins_upload_playstore_sa" + "name": "jenkins_upload_playstore_sa", + "title": "Jenkins: Upload Play Store SA" }
--- pinned/mimi_seed_auth_start +++ observed/mimi_seed_auth_start { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Mimi Seed: Auth start" + }, "description": "Google OAuth 로그인 링크를 발급하고 백그라운드 콜백 서버를 시작. 응답에 포함된 URL을 브라우저에서 열고 승인하면 localhost:9876으로 자동 콜백 → 토큰이 ~/.mimi-seed/tokens.json에 저장됨. 이후 playstore_*, firebase_*, admob_* 등 다른 MCP 도구 바로 호출 가능. domains 로 필요한 권한 도메인만 골라 요청 가능 (미지정 시 전체). 재로그인 시 기존 부여 권한은 유지되고 새 권한만 추가됨(incremental). 토큰 만료(invalid_rapt) / 재인증 필요 시 사용. 10분 내 완료해야 함.", "execution": { "taskSupport": "forbidden" - "description": "요청할 권한 도메인 서브셋 (미지정 시 전체). 가능한 값: firebase, gcp, admob, playstore, googleads, gsc, ga4, youtube. 예: [\"ga4\",\"googleads\"] — 기존에 부여된 다른 도메인 권한은 유지된다.", + "description": "요청할 권한 도메인 서브셋 (미지정 시 전체). 가능한 값: firebase, gcp, admob, playstore, googleads, gsc, ga4, youtube, youtube_analytics. 예: [\"ga4\",\"googleads\"] — 기존에 부여된 다른 도메인 권한은 유지된다.", "items": { "enum": [ "firebase", - "youtube" + "youtube", + "youtube_analytics" ], "type": "string" }, + }, + "expectedChannelId": { + "description": "이 채널로 로그인했는지 검증한 뒤 저장. profile 필수. Google 로그인에서 해당 개인/브랜드 채널을 선택하세요.", + "pattern": "^UC[\\w-]{22}$", + "type": "string" + }, + "profile": { + "description": "계정/채널별 Google 로그인 프로필. 생략하면 기존 기본 로그인.", + "pattern": "^[a-z0-9][a-z0-9_-]{0,63}$", + "type": "string" } }, "type": "object" - "name": "mimi_seed_auth_start" + "name": "mimi_seed_auth_start", + "title": "Mimi Seed: Auth start" }
--- pinned/mimi_seed_auth_status +++ observed/mimi_seed_auth_status { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Mimi Seed: Auth status" + }, "description": "Mimi Seed MCP 인증 상태 확인 (만료 시 refresh_token으로 자동 갱신 시도)", "execution": { "taskSupport": "forbidden" - "properties": {}, + "additionalProperties": false, + "properties": { + "profile": { + "description": "확인할 Google 로그인 프로필. 저장된 프로필 목록도 반환.", + "pattern": "^[a-z0-9][a-z0-9_-]{0,63}$", + "type": "string" + } + }, "type": "object" }, - "name": "mimi_seed_auth_status" + "name": "mimi_seed_auth_status", + "title": "Mimi Seed: Auth status" }
--- pinned/mimi_seed_remote_sync_credentials +++ observed/mimi_seed_remote_sync_credentials { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Mimi Seed: Remote sync credentials" + }, "description": "로컬 ~/.mimi-seed의 App Store Connect 키와 패키지별 Google Play 서비스 계정을 Mimi Seed 원격 MCP에 검증 후 암호화 동기화합니다. 기본은 미리보기이며 실제 비밀값 전송에는 confirm=true가 필요합니다. 로컬 Google OAuth tokens.json은 보안 및 OAuth 클라이언트 호환성 때문에 복사하지 않습니다.", "execution": { "taskSupport": "forbidden" - "description": "특정 Play 패키지만 동기화", + "description": "특정 Play 패키지만 동기화 — playstore_register_service_account 로 등록된 패키지명만 허용", "items": { + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" }, "type": "array" - "name": "mimi_seed_remote_sync_credentials" + "name": "mimi_seed_remote_sync_credentials", + "title": "Mimi Seed: Remote sync credentials" }
--- pinned/mimi_seed_status +++ observed/mimi_seed_status { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Mimi Seed: Status" + }, "description": "⭐ 새 세션을 시작하거나 \"뭐가 연결됐지?\" 라는 질문엔 이 도구를 먼저 호출하세요. 전체 서비스(Google OAuth / Play SA / App Store / Jenkins / CI / Google Ads / Facebook / Instagram / Threads / TikTok Business / BigQuery) 설정 상태를 한 번에 스캔해 ✅ / ❌ 트래픽 라이트 리포트와 번호 매긴 다음 단계를 반환합니다. 미설정 서비스마다 어떤 도구를 호출하면 되는지 구체적으로 알려줍니다.", "execution": { "taskSupport": "forbidden" - "name": "mimi_seed_status" + "name": "mimi_seed_status", + "title": "Mimi Seed: Status" }
+ tool added: naver_check_page
+ tool added: naver_indexnow_submit
--- pinned/playstore_cancel_recovery_action +++ observed/playstore_cancel_recovery_action { + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Play Store: Cancel recovery action" + }, "description": "진행 중인 복구 액션을 취소한다 — apprecovery.cancel. 아직 받지 않은 기기에는 더 이상 나가지 않는다. 이미 적용된 기기는 되돌아가지 않는다. confirm 필요.", "execution": { "taskSupport": "forbidden" + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" } }, - "name": "playstore_cancel_recovery_action" + "name": "playstore_cancel_recovery_action", + "title": "Play Store: Cancel recovery action" }
--- pinned/playstore_check_submission_risks +++ observed/playstore_check_submission_risks { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Play Store: Check submission risks" + }, "description": "Google Play 제출 전 위험 요소를 자동으로 점검합니다. 블로커(반드시 수정)와 경고(권장 수정)로 분류하여 반환합니다. 점검 항목: 리스팅 완성도(제목/설명/짧은설명), 스크린샷 수, 아이콘, 빌드 존재 여부, 연락처.", "execution": { "taskSupport": "forbidden" + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" } }, - "name": "playstore_check_submission_risks" + "name": "playstore_check_submission_risks", + "title": "Play Store: Check submission risks" }
--- pinned/playstore_create_onetime_product +++ observed/playstore_create_onetime_product { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Play Store: Create onetime product" + }, "description": "Google Play에 일회성 인앱 상품(소비성 또는 비소비성)을 생성. Play Console 권한: \"Manage store presence\" 필요. 생성 후 Console에서 활성화 필요.", "execution": { "taskSupport": "forbidden" + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" }, "price": { - "name": "playstore_create_onetime_product" + "name": "playstore_create_onetime_product", + "title": "Play Store: Create onetime product" }
--- pinned/playstore_create_recovery_action +++ observed/playstore_create_recovery_action { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Play Store: Create recovery action" + }, "description": "앱 복구 액션을 DRAFT 상태로 만든다 — apprecovery.create. 만들기만 하고 배포하지 않는다 (배포는 playstore_deploy_recovery_action). 대상은 allUsers 또는 versionCodes / versionRange 중 하나로 정한다 — allUsers 와 버전 지정은 함께 못 쓴다. ⚠️ 배포 후에는 대상을 만들 때 고른 기준 안에서만 넓힐 수 있다. 범위를 신중히 잡을 것. 이건 롤백이 아니라 \"고친 버전으로 강제 업데이트\"다 — 먼저 정상 빌드를 올려 둬야 의미가 있다.", "execution": { "taskSupport": "forbidden" + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" }, "regions": { - "name": "playstore_create_recovery_action" + "name": "playstore_create_recovery_action", + "title": "Play Store: Create recovery action" }
--- pinned/playstore_create_subscription +++ observed/playstore_create_subscription { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Play Store: Create subscription" + }, "description": "Google Play에 자동 갱신 구독을 생성하고 baseplan을 활성화. 구독 생성 → baseplan(가격·주기) 추가 → 자동 활성화. 이미 같은 productId가 있으면 생성 실패 (Play API 특성상 upsert 미지원).", "execution": { "taskSupport": "forbidden" + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" }, "period": { - "name": "playstore_create_subscription" + "name": "playstore_create_subscription", + "title": "Play Store: Create subscription" }
--- pinned/playstore_delete_all_images +++ observed/playstore_delete_all_images { - "description": "Google Play 리스팅 특정 imageType의 이미지 전체 삭제 (교체 전 정리). ⚠️ commit이 Play Console의 미게시 리스팅 변경을 덮어쓸 수 있음.", + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Play Store: Delete all images" + }, + "description": "Google Play 리스팅 특정 imageType의 이미지 전체 삭제 (교체 전 정리). ⚠️ commit이 Play Console의 미게시 리스팅 변경을 덮어쓸 수 있음. ⚠️ 안전 가드: confirm 생략/false 면 아무것도 바꾸지 않고 dry-run preview 만 반환한다. 사용자 명시 승인 후 confirm: true 로 재호출.", "execution": { "taskSupport": "forbidden" }, + "confirm": { + "description": "true 명시 시에만 실제 실행. 생략/false 면 dry-run preview 만 반환 (비가역·공개 사고 차단).", + "type": "boolean" + }, "imageType": { "enum": [ "featureGraphic", + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" } }, - "name": "playstore_delete_all_images" + "name": "playstore_delete_all_images", + "title": "Play Store: Delete all images" }
--- pinned/playstore_delete_product +++ observed/playstore_delete_product { - "description": "⚠️ 비가역. Google Play IAP 상품 삭제. 활성 baseplan + 구독자 있는 구독은 삭제 불가.", + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Play Store: Delete product" + }, + "description": "⚠️ 비가역. Google Play IAP 상품 삭제. 활성 baseplan + 구독자 있는 구독은 삭제 불가. ⚠️ 안전 가드: confirm 생략/false 면 아무것도 바꾸지 않고 dry-run preview 만 반환한다. 사용자 명시 승인 후 confirm: true 로 재호출.", "execution": { "taskSupport": "forbidden" }, + "confirm": { + "description": "true 명시 시에만 실제 실행. 생략/false 면 dry-run preview 만 반환 (비가역·공개 사고 차단).", + "type": "boolean" + }, "packageName": { "description": "패키지명", + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" }, "productId": { - "name": "playstore_delete_product" + "name": "playstore_delete_product", + "title": "Play Store: Delete product" }
--- pinned/playstore_delete_service_account +++ observed/playstore_delete_service_account { - "description": "등록된 패키지별 서비스 계정 삭제. default(레거시) SA는 영향 없음.", + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": false, + "readOnlyHint": false, + "title": "Play Store: Delete service account" + }, + "description": "등록된 패키지별 서비스 계정 삭제. default(레거시) SA는 영향 없음. ⚠️ 안전 가드: confirm 생략/false 면 아무것도 바꾸지 않고 dry-run preview 만 반환한다. 사용자 명시 승인 후 confirm: true 로 재호출.", "execution": { "taskSupport": "forbidden" }, + "confirm": { + "description": "true 명시 시에만 실제 실행. 생략/false 면 dry-run preview 만 반환 (비가역·공개 사고 차단).", + "type": "boolean" + }, "packageName": { "description": "삭제할 패키지명", + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" } }, - "name": "playstore_delete_service_account" + "name": "playstore_delete_service_account", + "title": "Play Store: Delete service account" }
--- pinned/playstore_deploy_recovery_action +++ observed/playstore_deploy_recovery_action { + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Play Store: Deploy recovery action" + }, "description": "DRAFT 복구 액션을 실제로 배포한다 — apprecovery.deploy. ⚠️ 대상 사용자 기기에 원격 인앱 업데이트가 나간다. 되돌리려면 취소해야 하고, 이미 적용된 기기는 되돌아가지 않는다. 배포 전 playstore_list_recovery_actions 로 대상 범위를 반드시 재확인할 것. confirm 필요.", "execution": { "taskSupport": "forbidden" + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" } }, - "name": "playstore_deploy_recovery_action" + "name": "playstore_deploy_recovery_action", + "title": "Play Store: Deploy recovery action" }
--- pinned/playstore_get_app +++ observed/playstore_get_app { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Play Store: Get app" + }, "description": "Google Play 앱 세부정보 조회 — 개발자 연락처(이메일·전화·웹사이트)·기본 언어 등 (edits.details). 수정은 playstore_update_details.", "execution": { "taskSupport": "forbidden" - "description": "패키지명 (예: com.findthem.app)", + "description": "패키지명 (예: com.example.app)", + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" } }, - "name": "playstore_get_app" + "name": "playstore_get_app", + "title": "Play Store: Get app" }
--- pinned/playstore_get_financial_report +++ observed/playstore_get_financial_report { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Play Store: Get financial report" + }, "description": "Play 재무 리포트를 내려받아 파싱·집계한다 = **Play 실매출의 기준선**. 분석 이벤트로는 라이선스 테스터·내부 테스트 결제를 실결제와 구분할 수 없다 (둘 다 install_source 가 com.android.vending 이다). 청구가 0원인 테스터 주문은 이 리포트에 **아예 나타나지 않으므로**, 여기 없으면 실매출이 아니다. earnings: Transaction Type 이 Charge/Google fee/Tax/환불로 나뉘고 수수료·세금이 음수로 들어와 netByMerchantCurrency 는 이미 순액이다. **Charge 행만이 실제 구매다.** sales: 주문 번호 단위라 개별 주문을 짚을 때 쓴다. ⚠️ 정산 통화마다 파일이 따로 떨어지므로 한 달치가 여러 파일일 수 있다 — 전부 합쳐서 집계한다.", "execution": { "taskSupport": "forbidden" + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" }, "reportType": { - "name": "playstore_get_financial_report" + "name": "playstore_get_financial_report", + "title": "Play Store: Get financial report" }
--- pinned/playstore_get_listing +++ observed/playstore_get_listing { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Play Store: Get listing" + }, "description": "Google Play 스토어 리스팅 조회 (제목, 설명문 등)", "execution": { "taskSupport": "forbidden" + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" } }, - "name": "playstore_get_listing" + "name": "playstore_get_listing", + "title": "Play Store: Get listing" }
--- pinned/playstore_get_statistics +++ observed/playstore_get_statistics { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Play Store: Get statistics" + }, "description": "Google Play Developer Reporting API / Android vitals 통계 조회. ANR/Crash/Error count를 기간·버전·기기·국가 등으로 분해해 확인", "execution": { "taskSupport": "forbidden" + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" }, "pageSize": { - "name": "playstore_get_statistics" + "name": "playstore_get_statistics", + "title": "Play Store: Get statistics" }
--- pinned/playstore_list_financial_reports +++ observed/playstore_list_financial_reports { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Play Store: List financial reports" + }, "description": "Play 재무 리포트 파일 목록 (Cloud Storage 버킷). ⚠️ **Play Developer API 에는 매출 엔드포인트가 없다.** purchases.* 는 구매 토큰을 이미 알아야 하고 Reporting API 는 vitals 뿐이다. 실제 정산 데이터는 Play Console 이 매달 개발자 소유 GCS 버킷에 떨궈주는 CSV 가 유일한 소스라, 이 도구는 그 버킷을 훑는다. 버킷 이름(gs://pubsite_prod_...)은 Play Console > 다운로드 보고서 > 재무 에만 있고 API 로 못 얻는다 — ~/.mimi-seed/play-financials.json 에 한 번 저장해두면 이후 생략 가능. ⚠️ 접근 권한은 **GCP IAM 이 아니다.** 이 버킷은 Google 소유라 프로젝트에 roles/storage.* 를 줘도 닿지 않는다 — Play Console > 사용자 및 권한 에서 서비스 계정 이메일을 초대하고 \"재무 데이터 보기\"를 전체(Global)로 줘야 열린다. 앱 게시용 Play Developer API 권한과 별개라, 릴리스가 되는 계정이라고 리포트가 열려 있지는 않다. 재무 리포트는 월 마감 후에 올라오므로 이번 달 파일이 없는 것은 정상이다.", "execution": { "taskSupport": "forbidden" + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" }, "reportType": { - "name": "playstore_list_financial_reports" + "name": "playstore_list_financial_reports", + "title": "Play Store: List financial reports" }
--- pinned/playstore_list_images +++ observed/playstore_list_images { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Play Store: List images" + }, "description": "Google Play 리스팅 이미지 목록 조회 (imageType별)", "execution": { "taskSupport": "forbidden" + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" } }, - "name": "playstore_list_images" + "name": "playstore_list_images", + "title": "Play Store: List images" }
--- pinned/playstore_list_inapp_products +++ observed/playstore_list_inapp_products { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Play Store: List inapp products" + }, "description": "Google Play 인앱 상품 목록", "execution": { "taskSupport": "forbidden" + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" } }, - "name": "playstore_list_inapp_products" + "name": "playstore_list_inapp_products", + "title": "Play Store: List inapp products" }
--- pinned/playstore_list_products +++ observed/playstore_list_products { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Play Store: List products" + }, "description": "Google Play의 모든 IAP 상품(구독 + 일회성) 통합 조회. productId / name / status / type / price / currency 반환.", "execution": { "taskSupport": "forbidden" + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" } }, - "name": "playstore_list_products" + "name": "playstore_list_products", + "title": "Play Store: List products" }
--- pinned/playstore_list_recovery_actions +++ observed/playstore_list_recovery_actions { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Play Store: List recovery actions" + }, "description": "앱 복구 액션 목록을 조회한다 — 읽기 전용 (apprecovery.list). 이미 배포된 앱이 치명적으로 망가졌을 때 특정 버전 사용자에게 원격 인앱 업데이트를 밀어 넣는 장치다. 상태(DRAFT/ACTIVE/CANCELED)·생성·배포·취소 시각과 대상을 보여준다.", "execution": { "taskSupport": "forbidden" + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" }, "versionCode": { - "name": "playstore_list_recovery_actions" + "name": "playstore_list_recovery_actions", + "title": "Play Store: List recovery actions" }
--- pinned/playstore_list_reviews +++ observed/playstore_list_reviews { - "description": "Google Play 리뷰 목록 조회", + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Play Store: List reviews" + }, + "description": "Google Play 리뷰 목록 조회. developerComment 가 null 이면 미답변, 답변이 있으면 본문과 수정 시각을 반환한다 (답변은 리뷰당 하나 — playstore_reply_review 는 기존 답변을 교체한다).", "execution": { "taskSupport": "forbidden" }, + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" } }, - "name": "playstore_list_reviews" + "name": "playstore_list_reviews", + "title": "Play Store: List reviews" }
--- pinned/playstore_list_service_accounts +++ observed/playstore_list_service_accounts { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": false, + "readOnlyHint": true, + "title": "Play Store: List service accounts" + }, "description": "등록된 패키지별 서비스 계정 + default(레거시) SA 정보 요약. clientEmail / projectId 만 노출 (private_key 미노출).", "execution": { "taskSupport": "forbidden" - "name": "playstore_list_service_accounts" + "name": "playstore_list_service_accounts", + "title": "Play Store: List service accounts" }
--- pinned/playstore_list_subscriptions +++ observed/playstore_list_subscriptions { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Play Store: List subscriptions" + }, "description": "Google Play 구독 상품 목록", "execution": { "taskSupport": "forbidden" + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" } }, - "name": "playstore_list_subscriptions" + "name": "playstore_list_subscriptions", + "title": "Play Store: List subscriptions" }
--- pinned/playstore_list_tracks +++ observed/playstore_list_tracks { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Play Store: List tracks" + }, "description": "Google Play 릴리스 트랙 현황 (프로덕션/베타/알파/내부)", "execution": { "taskSupport": "forbidden" + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" } }, - "name": "playstore_list_tracks" + "name": "playstore_list_tracks", + "title": "Play Store: List tracks" }
--- pinned/playstore_plan_release +++ observed/playstore_plan_release { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Play Store: Plan release" + }, "description": "Google Play 배포 플랜 — 인증/빌드/메타데이터/스크린샷/정책 위험을 한 번에 점검하고 체크리스트로 반환합니다 (read-only, 아무것도 변경하지 않음). ⚠️ AI 호출자 지시: 응답을 받으면 미완료 항목을 반드시 TodoWrite로 사용자에게 먼저 보여주고, 사용자 동의 후 단계별로 기존 도구(playstore_update_listing, playstore_update_release_notes, playstore_submit_release 등)를 호출하세요. submit_release(status=completed)는 비가역이므로 반드시 명시 동의 필요.", "execution": { "taskSupport": "forbidden" + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" }, "track": { - "name": "playstore_plan_release" + "name": "playstore_plan_release", + "title": "Play Store: Plan release" }
--- pinned/playstore_promote_release +++ observed/playstore_promote_release { - "description": "Google Play 트랙 간 release promote — fromTrack(예: internal)의 versionCode를 toTrack(예: production)에 새 release로 추가. 단일 edit session에서 source 조회 → target 업데이트 → commit 까지 한 번에 처리. source의 releaseNotes를 자동 복사 (copyReleaseNotes=false 또는 releaseNotes로 덮어쓰기 가능). status=\"completed\" + production 으로 전체 출시, status=\"inProgress\" + userFraction 으로 단계 출시(예: 0.1 = 10%). target에 같은 versionCode가 이미 있으면 해당 항목을 교체. status=\"completed\"면 target 활성 release를 통째로 새 것으로 대체. ⚠️ status=\"completed\"는 비가역에 가까움. playstore_check_submission_risks로 사전 점검 권장. Play 가 자동 심사 전송을 거부하는 앱이면 changesNotSentForReview=true 로 자동 폴백해 커밋한다 — 이때 응답의 changesNotSentForReview=true 와 nextAction 을 사용자에게 전달할 것(콘솔에서 \"심사를 위해 전송\"을 눌러야 심사 시작). source 트랙 노트가 버전 문자열뿐인 플레이스홀더면 warnings 로 알린다 — 그대로 승격하면 대상 트랙의 다국어 노트가 덮인다.", + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Play Store: Promote release" + }, + "description": "Google Play 트랙 간 release promote — fromTrack(예: internal)의 versionCode를 toTrack(예: production)에 새 release로 추가. 단일 edit session에서 source 조회 → target 업데이트 → commit 까지 한 번에 처리. source의 releaseNotes를 자동 복사 (copyReleaseNotes=false 또는 releaseNotes로 덮어쓰기 가능). status=\"completed\" + production 으로 전체 출시, status=\"inProgress\" + userFraction 으로 단계 출시(예: 0.1 = 10%). target에 같은 versionCode가 이미 있으면 해당 항목을 교체. status=\"completed\"면 target 활성 release를 통째로 새 것으로 대체. ⚠️ status=\"completed\"는 비가역에 가까움. playstore_check_submission_risks로 사전 점검 권장. Play 가 자동 심사 전송을 거부하는 앱이면 changesNotSentForReview=true 로 자동 폴백해 커밋한다 — 이때 응답의 changesNotSentForReview=true 와 nextAction 을 사용자에게 전달할 것(콘솔에서 \"심사를 위해 전송\"을 눌러야 심사 시작). source 트랙 노트가 버전 문자열뿐인 플레이스홀더면 warnings 로 알린다 — 그대로 승격하면 대상 트랙의 다국어 노트가 덮인다. ⚠️ 안전 가드: confirm 생략/false 면 아무것도 바꾸지 않고 dry-run preview 만 반환한다. 사용자 명시 승인 후 confirm: true 로 재호출.", "execution": { "taskSupport": "forbidden" }, + "confirm": { + "description": "true 명시 시에만 실제 실행. 생략/false 면 dry-run preview 만 반환 (비가역·공개 사고 차단).", + "type": "boolean" + }, "copyReleaseNotes": { "description": "source releaseNotes 복사 여부 (기본 true)", "type": "boolean" + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" }, "releaseName": { - "name": "playstore_promote_release" + "name": "playstore_promote_release", + "title": "Play Store: Promote release" }
--- pinned/playstore_register_service_account +++ observed/playstore_register_service_account { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Play Store: Register service account" + }, "description": "Google Play 서비스 계정 JSON을 패키지 단위로 등록 (~/.mimi-seed/play-service-accounts/{packageName}.json, 0600 mode). 여러 앱이 서로 다른 GCP 프로젝트의 SA를 쓰는 환경 지원. 등록 후 해당 packageName으로 호출하는 모든 playstore_* 도구가 이 SA를 사용 (등록 안 된 패키지는 ~/.mimi-seed/play-service-account.json 의 default SA로 폴백). 먼저 playstore_verify_service_account 로 권한 확인 후 등록을 권장.", "execution": { "taskSupport": "forbidden" + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" }, "serviceAccountJson": { - "description": "서비스 계정 JSON 전체 내용 (문자열)", + "description": "서비스 계정 JSON 전체 내용 (문자열). serviceAccountJsonPath 와 둘 중 하나", "type": "string" }, + "serviceAccountJsonPath": { + "description": "권장 — iam_create_key 가 저장한 키 파일 절대경로 (~/.mimi-seed/keys/ 안만 허용). 개인키가 대화에 남지 않음", + "type": "string" + }, "skipVerify": { "description": "true면 사전 검증 건너뜀 (기본 false: 등록 전 verifyServiceAccountJson 실행)", "type": "boolean" - "packageName", - "serviceAccountJson" + "packageName" ], "type": "object" }, - "name": "playstore_register_service_account" + "name": "playstore_register_service_account", + "title": "Play Store: Register service account" }
--- pinned/playstore_replace_images +++ observed/playstore_replace_images { - "description": "Google Play 리스팅 이미지 일괄 교체 (한 edit 세션: deleteall → 순서대로 upload → commit). 스크린샷 5~8장 한 번에 교체 시 효율적. 업로드 순서가 스토어 노출 순서. ⚠️ commit이 Play Console의 미게시 리스팅 변경을 덮어쓸 수 있음.", + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Play Store: Replace images" + }, + "description": "Google Play 리스팅 이미지 일괄 교체 (한 edit 세션: deleteall → 순서대로 upload → commit). 스크린샷 5~8장 한 번에 교체 시 효율적. 업로드 순서가 스토어 노출 순서. ⚠️ commit이 Play Console의 미게시 리스팅 변경을 덮어쓸 수 있음. ⚠️ 안전 가드: confirm 생략/false 면 아무것도 바꾸지 않고 dry-run preview 만 반환한다. 사용자 명시 승인 후 confirm: true 로 재호출.", "execution": { "taskSupport": "forbidden" }, + "confirm": { + "description": "true 명시 시에만 실제 실행. 생략/false 면 dry-run preview 만 반환 (비가역·공개 사고 차단).", + "type": "boolean" + }, "filePaths": { "description": "업로드할 이미지 절대 경로 배열 (순서 = 노출 순서)", "items": { + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" } }, - "name": "playstore_replace_images" + "name": "playstore_replace_images", + "title": "Play Store: Replace images" }
--- pinned/playstore_reply_review +++ observed/playstore_reply_review { - "description": "Google Play 리뷰에 답변", + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Play Store: Reply review" + }, + "description": "Google Play 리뷰에 답변 ⚠️ 안전 가드: confirm 생략/false 면 아무것도 바꾸지 않고 dry-run preview 만 반환한다. 사용자 명시 승인 후 confirm: true 로 재호출.", "execution": { "taskSupport": "forbidden" }, + "confirm": { + "description": "true 명시 시에만 실제 실행. 생략/false 면 dry-run preview 만 반환 (비가역·공개 사고 차단).", + "type": "boolean" + }, "packageName": { "description": "패키지명", + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" }, "replyText": { - "name": "playstore_reply_review" + "name": "playstore_reply_review", + "title": "Play Store: Reply review" }
--- pinned/playstore_submit_release +++ observed/playstore_submit_release { - "description": "Google Play 트랙의 release status를 변경 — 일반적으로 draft → completed로 바꿔 검토/배포 큐에 진입시킬 때 사용. ⚠️ status=\"completed\"는 비가역에 가까움 (전체 출시 또는 Google 검토 시작). halted로 일시 중단은 가능하나 한 번 라이브된 release는 되돌리기 어려움. status 옵션: draft(검토 미시작) / inProgress(단계 출시) / completed(전체 출시) / halted(중단). playstore_check_submission_risks로 사전 점검 권장.", + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Play Store: Submit release" + }, + "description": "Google Play 트랙의 release status를 변경 — 일반적으로 draft → completed로 바꿔 검토/배포 큐에 진입시킬 때 사용. completed 전환은 해당 트랙의 릴리스 목록을 대상 릴리스 하나로 교체한다. changesNotSentForReview=true 응답이면 커밋만 완료된 것이며 Console에서 심사 전송이 필요하다. ⚠️ status=\"completed\"는 비가역에 가까움 (전체 출시 또는 Google 검토 시작). halted로 일시 중단은 가능하나 한 번 라이브된 release는 되돌리기 어려움. status 옵션: draft(검토 미시작) / inProgress(단계 출시) / completed(전체 출시) / halted(중단). playstore_check_submission_risks로 사전 점검 권장. ⚠️ 안전 가드: confirm 생략/false 면 아무것도 바꾸지 않고 dry-run preview 만 반환한다. 사용자 명시 승인 후 confirm: true 로 재호출.", "execution": { "taskSupport": "forbidden" }, + "confirm": { + "description": "true 명시 시에만 실제 실행. 생략/false 면 dry-run preview 만 반환 (비가역·공개 사고 차단).", + "type": "boolean" + }, "packageName": { "description": "패키지명 (예: com.example.app)", + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" }, "status": { - "name": "playstore_submit_release" + "name": "playstore_submit_release", + "title": "Play Store: Submit release" }
--- pinned/playstore_update_details +++ observed/playstore_update_details { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Play Store: Update details" + }, "description": "Google Play 앱 세부정보(개발자 연락처·기본 언어) 수정 — 연락처 이메일/전화/웹사이트, 기본 언어. 스토어 리스팅(제목·설명)과는 별개이며, 넘긴 필드만 부분 갱신(edits.details.patch). ⚠️ Console 에서 같은 앱을 편집·미게시 중이면 충돌할 수 있음.", "execution": { "taskSupport": "forbidden" + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" } }, - "name": "playstore_update_details" + "name": "playstore_update_details", + "title": "Play Store: Update details" }
--- pinned/playstore_update_listing +++ observed/playstore_update_listing { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Play Store: Update listing" + }, "description": "Google Play 스토어 리스팅 수정 또는 새 언어 생성. 기존 언어는 넘긴 필드만 부분 갱신(edits.listings.patch)해 생략한 필드와 프로모 영상(video)을 보존한다. 새 언어는 title·shortDescription·fullDescription을 모두 전달해야 하며 전체 리스팅을 생성한다. ⚠️ Play API 편집과 Console 동시 편집은 충돌 — Console에서 같은 리스팅을 편집·미게시 중이면 그 변경이 덮어써질 수 있음.", "execution": { "taskSupport": "forbidden" + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" }, "shortDescription": { - "name": "playstore_update_listing" + "name": "playstore_update_listing", + "title": "Play Store: Update listing" }
--- pinned/playstore_update_product +++ observed/playstore_update_product { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Play Store: Update product" + }, "description": "Google Play IAP 상품의 표시 이름 변경 (현재 name 필드만 수정 가능). productId / type / 가격은 변경 불가. 언어별 제목·설명은 playstore_update_product_listing / playstore_update_subscription_listing 을 쓴다.", "execution": { "taskSupport": "forbidden" + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" }, "productId": { - "name": "playstore_update_product" + "name": "playstore_update_product", + "title": "Play Store: Update product" }
--- pinned/playstore_update_product_listing +++ observed/playstore_update_product_listing { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Play Store: Update product listing" + }, "description": "Google Play 인앱 상품(소모성/비소모성)의 언어별 제목·설명을 갱신. 넘긴 로케일만 덮어쓰고 나머지 언어는 보존한다. 리스팅이 없는 언어의 사용자에게는 앱 기본 언어 리스팅이 대신 보인다 — 번역을 넣어야 그 나라 결제창이 그 나라 말로 나온다. 구독은 playstore_update_subscription_listing 을 쓴다.", "execution": { "taskSupport": "forbidden" + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" }, "productId": { - "name": "playstore_update_product_listing" + "name": "playstore_update_product_listing", + "title": "Play Store: Update product listing" }
--- pinned/playstore_update_product_state +++ observed/playstore_update_product_state { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Play Store: Update product state" + }, "description": "Google Play 인앱 상품의 구매 옵션을 활성화/비활성화 — Play Console 의 DRAFT → 활성 토글. DRAFT 인 상품은 가격이 앱에 안 내려오므로 만들고 활성화하지 않으면 상점 화면이 비어 보인다. purchaseOptionId 는 playstore_list_inapp_products 의 purchaseOptions[].purchaseOptionId (보통 \"base\").", "execution": { "taskSupport": "forbidden" + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" }, "productId": { - "name": "playstore_update_product_state" + "name": "playstore_update_product_state", + "title": "Play Store: Update product state" }
--- pinned/playstore_update_release_notes +++ observed/playstore_update_release_notes { - "description": "Google Play 트랙 릴리스의 '최근 변경사항'(releaseNotes) 업데이트. versionCode로 타겟 릴리스 지정. 다른 언어/release는 보존. 이미 라이브(completed) 상태도 noteOnly 편집 가능", + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Play Store: Update release notes" + }, + "description": "Google Play 트랙 릴리스의 '최근 변경사항'(releaseNotes) 업데이트. 다른 언어/release는 보존. 이미 라이브(completed) 상태도 noteOnly 편집 가능. versionCode 를 주면 그 릴리스, 생략하면 트랙의 최신 릴리스(versionCode 최대)에 적용한다. ⚠️ 지정한 트랙에만 적용 — 다른 트랙에는 자동 복사되지 않음 (Google Play 정책: promote_release 시점에 노트 캐리됨). 동일 노트를 여러 트랙에 즉시 반영하려면 syncTracks 사용 — 1차 track 반영 후 트랙별 최신 릴리스에 순차 적용. syncTracks 는 versionCode 생략 시에만 쓸 수 있다 (트랙마다 같은 versionCode 가 있다는 보장이 없어 함께 주면 거부).", "execution": { "taskSupport": "forbidden" }, + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" }, + "syncTracks": { + "description": "추가로 동일 노트 적용할 트랙 배열 (예: [\"production\"]). versionCode 생략 시에만. 1차 track 반영 후 순차 동기화.", + "items": { + "enum": [ + "production", + "beta", + "alpha", + "internal" + ], + "type": "string" + }, + "type": "array" + }, "text": { "description": "릴리스 노트 본문 (500자 이내)", "type": "string" - "description": "릴리스 트랙", + "description": "릴리스 트랙 (1차 적용 트랙)", "enum": [ "production", "beta", - "description": "대상 versionCode (문자열, 예: \"40\")", + "description": "대상 versionCode (문자열, 예: \"40\"). 생략 시 트랙의 최신 릴리스", "type": "string" } }, - "versionCode", "language", "text" ], - "name": "playstore_update_release_notes" + "name": "playstore_update_release_notes", + "title": "Play Store: Update release notes" }
--- pinned/playstore_update_subscription_listing +++ observed/playstore_update_subscription_listing { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Play Store: Update subscription listing" + }, "description": "Google Play 구독 상품의 언어별 제목·설명·혜택(benefits)을 갱신. 넘긴 로케일만 덮어쓰고 나머지 언어는 보존한다. benefits 는 스토어 구매창에 불릿으로 나오는 항목이라 한 줄에 몰아넣지 말고 항목을 나눠 넣는다 (최대 4개).", "execution": { "taskSupport": "forbidden" + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" }, "productId": { - "name": "playstore_update_subscription_listing" + "name": "playstore_update_subscription_listing", + "title": "Play Store: Update subscription listing" }
--- pinned/playstore_upload_data_safety +++ observed/playstore_upload_data_safety { + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Play Store: Upload data safety" + }, "description": "Play 데이터 안전(Safety Labels) 선언을 업로드한다 — POST applications/{packageName}/dataSafety. 오래 Console 전용으로 알려졌던 항목이지만 API 가 있다. 입력은 Play Console 이 내려주는 **CSV 원문**이다 (Console > 앱 콘텐츠 > 데이터 안전 > 내보내기). ⚠️ 기존 제출을 통째로 덮어쓴다 — 부분 갱신이 아니므로 항상 최신 전체 CSV 를 보낼 것. 콘텐츠 등급·타깃 연령 설문은 여전히 API 가 없다 (Console 전용).", "execution": { "taskSupport": "forbidden" + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" } }, - "name": "playstore_upload_data_safety" + "name": "playstore_upload_data_safety", + "title": "Play Store: Upload data safety" }
--- pinned/playstore_upload_image +++ observed/playstore_upload_image { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Play Store: Upload image" + }, "description": "Google Play 리스팅 이미지 단일 업로드 (기존 이미지 유지). featureGraphic 1024x500 / icon 512x512 / phoneScreenshots 320~3840px. ⚠️ 이 작업은 edit을 commit하므로 Play Console의 미게시(저장 전) 리스팅 변경을 덮어쓸 수 있음 — Console에서 같은 앱을 편집 중이면 먼저 저장·게시하거나 텍스트도 update_listing으로 처리하세요.", "execution": { "taskSupport": "forbidden" + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" } }, - "name": "playstore_upload_image" + "name": "playstore_upload_image", + "title": "Play Store: Upload image" }
--- pinned/playstore_verify_service_account +++ observed/playstore_verify_service_account { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Play Store: Verify service account" + }, "description": "서비스 계정 JSON이 주어진 packageName에 대해 Play Developer API 호출 가능한지 + 'View financial data' 권한까지 있는지 검증. onesub 같은 서버가 Play 영수증을 백그라운드로 검증하려면 OAuth 토큰 대신 서비스 계정 JSON이 필요 — 이 도구로 붙여넣기 전에 유효성 확인. 성공 시 clientEmail + projectId 반환. 실패 시 어느 단계(parse/auth/api)에서 왜 막혔는지 단계별로 안내. (이 도구는 서비스 계정 자격증명만 사용 — 로그인한 사용자의 OAuth 토큰은 건드리지 않음)", "execution": { "taskSupport": "forbidden" - "description": "검증할 Android 앱의 패키지명 (예: com.findthem.app)", + "description": "검증할 Android 앱의 패키지명 (예: com.example.app)", + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" }, "serviceAccountJson": { - "description": "서비스 계정 JSON 전체 내용 (문자열). Google Cloud Console → IAM & Admin → Service Accounts → Keys → Create new key → JSON으로 다운받은 파일의 내용", + "description": "서비스 계정 JSON 전체 내용 (문자열). serviceAccountJsonPath 와 둘 중 하나. 문자열로 넘기면 개인키가 대화 기록에 남는다", "type": "string" + }, + "serviceAccountJsonPath": { + "description": "권장 — iam_create_key 가 저장한 키 파일 절대경로 (~/.mimi-seed/keys/ 안만 허용). 개인키가 대화에 남지 않음", + "type": "string" } }, "required": [ - "serviceAccountJson", "packageName" ], "type": "object" - "name": "playstore_verify_service_account" + "name": "playstore_verify_service_account", + "title": "Play Store: Verify service account" }
--- pinned/release_status +++ observed/release_status { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Release status" + }, "description": "양 스토어의 동일 버전 상태를 한 번에 조회 — 1.4.x 배포 시 \"Play 는 production?\", \"ASC 는 심사중?\" 을 list_versions + list_tracks 2회 호출 + grep 으로 합치던 멘탈 부담을 단일 응답으로 줄임. App Store: appId 가 있을 때 listVersions 에서 version 일치 항목의 state/releaseType/attached build/createdDate. Play Store: packageName 이 있을 때 listTracks 에서 동일 versionName 또는 versionCode 가 있는 모든 트랙의 status/versionCodes. appId 또는 packageName 둘 다 비어 있으면 에러. 둘 중 하나만 줘도 그 스토어 상태만 조회 가능.", "execution": { "taskSupport": "forbidden" + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" }, "version": { - "name": "release_status" + "name": "release_status", + "title": "Release status" }
--- pinned/screenshot_validate +++ observed/screenshot_validate { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": false, + "readOnlyHint": true, + "title": "Screenshot validate" + }, "description": "로컬 스크린샷 파일의 해상도·파일크기·종횡비를 App Store / Play Store 규격과 비교 검증합니다. PNG/JPEG 파일 경로를 배열로 받아 각 파일의 통과 여부와 문제점을 반환합니다. platform: \"ios\" 또는 \"android\" (기본: ios) iOS displayType 예시: APP_IPHONE_69, APP_IPHONE_67, APP_IPHONE_65, APP_IPAD_PRO_3GEN_129 Android imageType 예시: phoneScreenshots, sevenInchScreenshots, tenInchScreenshots, featureGraphic 업로드 전 미리 검사하여 리젝 방지에 활용하세요.", "execution": { "taskSupport": "forbidden" - "name": "screenshot_validate" + "name": "screenshot_validate", + "title": "Screenshot validate" }
--- pinned/setup_playstore_connection +++ observed/setup_playstore_connection { - "description": "Play Store 서비스 계정을 한 번에 설정합니다 (SA 생성 → JSON 키 발급 → 로컬 등록). iam_create_service_account → iam_create_key → playstore_register_service_account 를 순서대로 자동 실행. 완료 후 Play Console에서 서비스 계정 이메일을 초대하는 안내(수동 1단계)가 포함됩니다. 이미 같은 accountId의 SA가 존재하면 키만 새로 발급하고 등록합니다.", + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Setup Play Store connection" + }, + "description": "Play Store 서비스 계정을 한 번에 설정합니다 (SA 생성 → JSON 키 발급 → 로컬 등록). iam_create_service_account → iam_create_key → playstore_register_service_account 를 순서대로 자동 실행. 완료 후 Play Console에서 서비스 계정 이메일을 초대하는 안내(수동 1단계)가 포함됩니다. 이미 같은 accountId의 SA가 존재하면 키만 새로 발급하고 등록합니다. ⚠️ 안전 가드: confirm 생략/false 면 아무것도 바꾸지 않고 dry-run preview 만 반환한다. 사용자 명시 승인 후 confirm: true 로 재호출.", "execution": { "taskSupport": "forbidden" }, + "confirm": { + "description": "true 명시 시에만 실제 실행. 생략/false 면 dry-run preview 만 반환 (비가역·공개 사고 차단).", + "type": "boolean" + }, "packageName": { "description": "Android 패키지명 (예: com.example.app)", + "maxLength": 255, + "pattern": "^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)+$", "type": "string" }, "projectId": { - "name": "setup_playstore_connection" + "name": "setup_playstore_connection", + "title": "Setup Play Store connection" }
--- pinned/threads_current_config +++ observed/threads_current_config { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": false, + "readOnlyHint": true, + "title": "Threads: Current config" + }, "description": "현재 선택된 Threads 연결 설정을 확인합니다. 프로젝트 매핑 또는 profile 인자를 따릅니다.", "execution": { "taskSupport": "forbidden" - "name": "threads_current_config" + "name": "threads_current_config", + "title": "Threads: Current config" }
--- pinned/threads_get_account +++ observed/threads_get_account { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "Threads: Get account" + }, "description": "Threads 계정 정보 조회 + 저장된 토큰 유효성 검증.", "execution": { "taskSupport": "forbidden" - "name": "threads_get_account" + "name": "threads_get_account", + "title": "Threads: Get account" }
--- pinned/threads_post +++ observed/threads_post { - "description": "Threads에 게시합니다. 텍스트 전용이 기본이며, imageUrl을 주면 이미지 게시. text에는 링크·멘션(@)·해시태그를 포함할 수 있고 줄바꿈 \\n 사용. 게시물당 최대 500자. imageUrl은 public URL이어야 합니다 (Graph API 제약). 로컬 파일은 미리 S3/R2/Cloudinary 등에 업로드 필요. 2-step API: container 생성(/threads) → threads_publish. 이미지는 처리 완료까지 자동 대기.", + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Threads: Post" + }, + "description": "Threads에 게시합니다. 텍스트 전용이 기본이며, imageUrl을 주면 이미지 게시. text에는 링크·멘션(@)·해시태그를 포함할 수 있고 줄바꿈 \\n 사용. 게시물당 최대 500자. imageUrl은 public URL이어야 합니다 (Graph API 제약). 로컬 파일은 미리 S3/R2/Cloudinary 등에 업로드 필요. 2-step API: container 생성(/threads) → threads_publish. 이미지는 처리 완료까지 자동 대기. ⚠️ 안전 가드: confirm 생략/false 면 아무것도 바꾸지 않고 dry-run preview 만 반환한다. 사용자 명시 승인 후 confirm: true 로 재호출.", "execution": { "taskSupport": "forbidden" }, + "confirm": { + "description": "true 명시 시에만 실제 실행. 생략/false 면 dry-run preview 만 반환 (비가역·공개 사고 차단).", + "type": "boolean" + }, "imageUrl": { "description": "이미지의 public URL (생략 시 텍스트 전용 게시)", "format": "uri", - "name": "threads_post" + "name": "threads_post", + "title": "Threads: Post" }
--- pinned/threads_post_carousel +++ observed/threads_post_carousel { - "description": "여러 이미지를 캐러셀로 Threads에 게시합니다. 2~20장 (인스타는 10장, Threads는 20장). 모든 이미지는 public URL이어야 함. 각 이미지 처리 완료까지 자동 대기. 3-step API: 각 이미지 children container → carousel container → publish.", + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Threads: Post carousel" + }, + "description": "여러 이미지를 캐러셀로 Threads에 게시합니다. 2~20장 (인스타는 10장, Threads는 20장). 모든 이미지는 public URL이어야 함. 각 이미지 처리 완료까지 자동 대기. 3-step API: 각 이미지 children container → carousel container → publish. ⚠️ 안전 가드: confirm 생략/false 면 아무것도 바꾸지 않고 dry-run preview 만 반환한다. 사용자 명시 승인 후 confirm: true 로 재호출.", "execution": { "taskSupport": "forbidden" }, + "confirm": { + "description": "true 명시 시에만 실제 실행. 생략/false 면 dry-run preview 만 반환 (비가역·공개 사고 차단).", + "type": "boolean" + }, "imageUrls": { "description": "이미지 URL 배열 (2~20장)", "items": { - "name": "threads_post_carousel" + "name": "threads_post_carousel", + "title": "Threads: Post carousel" }
--- pinned/threads_post_video +++ observed/threads_post_video { - "description": "public URL의 영상을 Threads에 게시합니다. Meta가 videoUrl을 직접 가져가므로 외부에서 인증 없이 접근 가능한 URL이어야 합니다. 3-step API: VIDEO container 생성 → 처리 완료 자동 대기 → threads_publish. 공개 게시 작업이므로 같은 턴에 사용자의 명시 승인을 받은 뒤 호출하세요.", + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Threads: Post video" + }, + "description": "public URL의 영상을 Threads에 게시합니다. Meta가 videoUrl을 직접 가져가므로 외부에서 인증 없이 접근 가능한 URL이어야 합니다. 3-step API: VIDEO container 생성 → 처리 완료 자동 대기 → threads_publish. 공개 게시 작업이므로 같은 턴에 사용자의 명시 승인을 받은 뒤 호출하세요. ⚠️ 안전 가드: confirm 생략/false 면 아무것도 바꾸지 않고 dry-run preview 만 반환한다. 사용자 명시 승인 후 confirm: true 로 재호출.", "execution": { "taskSupport": "forbidden" }, + "confirm": { + "description": "true 명시 시에만 실제 실행. 생략/false 면 dry-run preview 만 반환 (비가역·공개 사고 차단).", + "type": "boolean" + }, "profile": { "description": "저장/사용할 소셜 프로필 ID. 생략 시 .mimi-seed.json의 socialProfiles.threads, 없으면 기존 기본 설정", "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$", - "name": "threads_post_video" + "name": "threads_post_video", + "title": "Threads: Post video" }
--- pinned/threads_refresh_token +++ observed/threads_refresh_token { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Threads: Refresh token" + }, "description": "저장된 Threads long-lived 토큰을 만료 전에 공식 refresh_access_token endpoint로 갱신합니다. 성공하면 새 토큰과 실제 expires_in을 저장하고 계정을 다시 검증합니다. 이미 만료·철회된 토큰은 갱신할 수 없으므로 mimi-seed auth threads로 재연결하세요.", "execution": { "taskSupport": "forbidden" - "name": "threads_refresh_token" + "name": "threads_refresh_token", + "title": "Threads: Refresh token" }
--- pinned/threads_save_config +++ observed/threads_save_config { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Threads: Save config" + }, "description": "Threads 토큰을 ~/.mimi-seed/threads.json (mode 0600)에 저장합니다. accessToken은 Threads Graph API long-lived 토큰 (약 60일). userId 미입력 시 토큰으로 자동 조회 (GET /me). profile 지정 시 ~/.mimi-seed/social-profiles/<profile>.json에 저장합니다. 저장 직후 토큰 유효성도 자동 검증. Instagram 과 별개 계정·별개 토큰입니다 (threads_basic, threads_content_publish 권한 필요).", "execution": { "taskSupport": "forbidden" - "name": "threads_save_config" + "name": "threads_save_config", + "title": "Threads: Save config" }
--- pinned/tiktok_business_auth_status +++ observed/tiktok_business_auth_status { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "TikTok Business: Auth status" + }, "description": "TikTok API for Business Organic API 연결과 권한 상태를 확인합니다. 만료 5분 전이면 refresh token으로 access token을 자동 갱신합니다. 토큰·앱 시크릿은 응답하지 않습니다. 미연결이면 `mimi-seed auth tiktok`을 실행하세요.", "execution": { "taskSupport": "forbidden" - "name": "tiktok_business_auth_status" + "name": "tiktok_business_auth_status", + "title": "TikTok Business: Auth status" }
--- pinned/tiktok_business_get_account +++ observed/tiktok_business_get_account { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "TikTok Business: Get account" + }, "description": "연결된 owned TikTok Business Account 프로필을 조회하고 현재 토큰으로 접근 가능한지 검증합니다.", "execution": { "taskSupport": "forbidden" - "name": "tiktok_business_get_account" + "name": "tiktok_business_get_account", + "title": "TikTok Business: Get account" }
--- pinned/tiktok_business_get_publish_status +++ observed/tiktok_business_get_publish_status { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "TikTok Business: Get publish status" + }, "description": "TikTok 게시 처리 상태를 조회하고 로컬 감사 로그의 pending/published/failed 상태를 갱신합니다.", "execution": { "taskSupport": "forbidden" - "name": "tiktok_business_get_publish_status" + "name": "tiktok_business_get_publish_status", + "title": "TikTok Business: Get publish status" }
--- pinned/tiktok_business_get_video_settings +++ observed/tiktok_business_get_video_settings { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "TikTok Business: Get video settings" + }, "description": "게시 전에 계정별 최대 영상 길이와 댓글·듀엣·스티치 설정을 조회합니다.", "execution": { "taskSupport": "forbidden" - "name": "tiktok_business_get_video_settings" + "name": "tiktok_business_get_video_settings", + "title": "TikTok Business: Get video settings" }
--- pinned/tiktok_business_list_publish_audits +++ observed/tiktok_business_list_publish_audits { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": false, + "readOnlyHint": true, + "title": "TikTok Business: List publish audits" + }, "description": "로컬 TikTok 게시 감사 로그를 최신순으로 조회합니다. 토큰·앱 시크릿·서명 URL 쿼리는 저장하거나 반환하지 않습니다.", "execution": { "taskSupport": "forbidden" - "name": "tiktok_business_list_publish_audits" + "name": "tiktok_business_list_publish_audits", + "title": "TikTok Business: List publish audits" }
--- pinned/tiktok_business_plan_video_post +++ observed/tiktok_business_plan_video_post { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "TikTok Business: Plan video post" + }, "description": "TikTok 공개 게시 전용 계획을 만들고 30분 동안 로컬에 보관합니다. 로컬 원본을 ffprobe로 검사하고 SHA-256으로 중복 게시를 차단하며 계정별 영상 설정과 대조합니다. videoUrl은 TikTok 앱에서 검증한 도메인의 HTTPS URL이어야 하고 최소 30분 이상 유효해야 합니다. 이 도구는 TikTok에 게시하지 않습니다. 검토 후 tiktok_business_publish_video를 별도로 호출하세요.", "execution": { "taskSupport": "forbidden" - "ffmpegPath": { - "description": "FFmpeg 절대경로. 생략하면 PATH의 ffprobe 사용", - "type": "string" - }, "isAiGenerated": { "default": true, "description": "AI 생성·변형 영상 고지", - "name": "tiktok_business_plan_video_post" + "name": "tiktok_business_plan_video_post", + "title": "TikTok Business: Plan video post" }
--- pinned/tiktok_business_publish_video +++ observed/tiktok_business_publish_video { + "annotations": { + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "TikTok Business: Publish video" + }, "description": "검증된 30분짜리 계획을 owned TikTok Business Account에 공개 게시합니다. 외부 공개 작업이므로 같은 턴에 사용자의 명시 승인을 받은 뒤 confirmPublish=true로 호출해야 합니다. POST 타임아웃은 결과 불명으로 감사 로그에 남고 자동 재시도를 막습니다. 성공 응답은 보통 pending이며 tiktok_business_get_publish_status로 완료를 확인하세요.", "execution": { "taskSupport": "forbidden" - "name": "tiktok_business_publish_video" + "name": "tiktok_business_publish_video", + "title": "TikTok Business: Publish video" }
--- pinned/video_add_local_asset +++ observed/video_add_local_asset { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": false, + "readOnlyHint": false, + "title": "Video: Add local asset" + }, "description": "사용자 소유 또는 별도 라이선스를 확보한 로컬 이미지·영상·오디오를 프로젝트에 복사해 등록합니다. filePath는 절대경로여야 하며 license와 출처 정보가 assets.json에 기록됩니다. reference-only 자료는 이 도구로 등록하지 마세요.", "execution": { "taskSupport": "forbidden" - "name": "video_add_local_asset" + "name": "video_add_local_asset", + "title": "Video: Add local asset" }
--- pinned/video_build_timeline +++ observed/video_build_timeline { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": false, + "readOnlyHint": false, + "title": "Video: Build timeline" + }, "description": "등록된 이미지·영상 자산을 장면 순서와 길이에 맞춰 timeline.json으로 조합합니다. assets.json에서 allowedForRendering=true이고 reference-only가 아닌 자산만 허용합니다. 화면 문구는 최종 렌더에서 쇼츠 스타일 자막(굵은 폰트·흰 글자·검정 외곽선)으로 번인되며, onScreenText 안의 **단어** 마크업은 하이라이트 컬러(기본 노랑)로 강조됩니다. 한 장면 자막은 3~5어절·최대 2줄로 짧게 쓰고, 하이라이트는 문장당 한 단어만 지정하세요.", "execution": { "taskSupport": "forbidden" - "name": "video_build_timeline" + "name": "video_build_timeline", + "title": "Video: Build timeline" }
--- pinned/video_download_stock_assets +++ observed/video_download_stock_assets { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Video: Download stock assets" + }, "description": "선택한 Pexels 스톡 영상을 프로젝트로 다운로드하고 출처·라이선스·해시를 assets.json에 기록합니다. confirm=false는 다운로드 계획만 반환합니다. 외부 파일 다운로드 전 사용자 승인을 받은 뒤 confirm=true로 다시 호출하세요. Pexels 공식 미디어 호스트만 허용하며 파일당 100MB, 호출당 5개로 제한합니다.", "execution": { "taskSupport": "forbidden" - "name": "video_download_stock_assets" + "name": "video_download_stock_assets", + "title": "Video: Download stock assets" }
--- pinned/video_generate_image +++ observed/video_generate_image { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Video: Generate image" + }, "description": "OpenAI Image API로 장면 이미지를 생성하고 프로젝트 자산으로 등록합니다. OPENAI_API_KEY가 필요합니다. 기본 모델은 gpt-image-2이며 이미지 바이트는 도구 응답에 넣지 않고 로컬 절대경로만 반환합니다. confirm=false는 생성 계획만 반환합니다. 비용이 발생하므로 사용자 승인 후 confirm=true로 호출하세요.", "execution": { "taskSupport": "forbidden" - "name": "video_generate_image" + "name": "video_generate_image", + "title": "Video: Generate image" }
--- pinned/video_job_status +++ observed/video_job_status { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": false, + "readOnlyHint": true, + "title": "Video: Job status" + }, "description": "video_render가 시작한 비동기 FFmpeg 작업의 상태와 결과 절대경로를 조회합니다. 실패한 경우 로그 마지막 부분을 함께 반환합니다.", "execution": { "taskSupport": "forbidden" - "name": "video_job_status" + "name": "video_job_status", + "title": "Video: Job status" }
--- pinned/video_plan_from_story +++ observed/video_plan_from_story { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Video: Plan from story" + }, "description": "정리된 story를 장면별 스토리보드로 변환하고 로컬 영상 프로젝트를 만듭니다. ANTHROPIC_API_KEY가 필요합니다. projectDir에는 project.json과 자산/리서치/렌더 폴더가 생성됩니다. 기존 project.json은 overwrite=true 없이는 덮어쓰지 않습니다.", "execution": { "taskSupport": "forbidden" - "name": "video_plan_from_story" + "name": "video_plan_from_story", + "title": "Video: Plan from story" }
--- pinned/video_render +++ observed/video_render { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": false, + "readOnlyHint": false, + "title": "Video: Render" + }, "description": "timeline.json과 등록 자산을 FFmpeg로 합성해 MP4 렌더 작업을 시작합니다. 이미지/영상 크롭, 장면 연결, 쇼츠 스타일 자막 번인(timeline.json의 captionStyle 적용), 선택적 배경음, H.264/yuv420p 출력을 지원합니다. confirm=false는 계획만 반환합니다. CPU를 사용하는 로컬 쓰기 작업이므로 승인 후 confirm=true로 호출하세요. 즉시 jobId를 반환하므로 video_job_status로 완료 여부를 확인하세요.", "execution": { "taskSupport": "forbidden" - "ffmpegPath": { - "description": "FFmpeg 실행 파일 경로. 생략하면 MIMI_SEED_FFMPEG_PATH 또는 PATH 사용", - "type": "string" - }, "outputFileName": { "default": "output.mp4", "type": "string" - "name": "video_render" + "name": "video_render", + "title": "Video: Render" }
--- pinned/video_research_youtube +++ observed/video_research_youtube { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Video: Research YouTube" + }, "description": "스토리보드 검색어나 지정 검색어로 YouTube 유사 영상을 조사합니다. YOUTUBE_API_KEY가 필요하며 결과는 research/youtube.json에 저장됩니다. 결과는 reference-only로 기록되어 영상 파일 다운로드나 렌더링 소스로 사용되지 않습니다.", "execution": { "taskSupport": "forbidden" - "name": "video_research_youtube" + "name": "video_research_youtube", + "title": "Video: Research YouTube" }
--- pinned/video_save_plan +++ observed/video_save_plan { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": false, + "readOnlyHint": false, + "title": "Video: Save plan" + }, "description": "에이전트가 직접 작성한 장면별 스토리보드를 project.json으로 저장합니다. API 키가 필요 없는 video_plan_from_story의 무료 대안입니다. 스토리보드(장면 분할·내레이션·화면 문구·시각 프롬프트)는 호출 전에 에이전트가 직접 설계하세요. 장면 durationSec 합계는 targetDurationSec와 일치해야 합니다(허용 오차 0.1초). 기존 project.json은 overwrite=true 없이는 덮어쓰지 않습니다.", "execution": { "taskSupport": "forbidden" - "name": "video_save_plan" + "name": "video_save_plan", + "title": "Video: Save plan" }
--- pinned/video_search_stock_assets +++ observed/video_search_stock_assets { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Video: Search stock assets" + }, "description": "스토리보드 검색어나 지정 검색어로 Pexels 라이선스 스톡 영상을 찾습니다. PEXELS_API_KEY가 필요하며 결과는 research/pexels.json에 저장됩니다. 검색만 수행하며 다운로드는 video_download_stock_assets로 별도 승인 후 실행합니다.", "execution": { "taskSupport": "forbidden" - "name": "video_search_stock_assets" + "name": "video_search_stock_assets", + "title": "Video: Search stock assets" }
--- pinned/video_synthesize_research +++ observed/video_synthesize_research { + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "Video: Synthesize research" + }, "description": "저장된 YouTube/Pexels 메타데이터와 사용자가 직접 관찰한 영상 메모를 독창적인 제작 방향으로 종합합니다. ANTHROPIC_API_KEY가 필요하며 결과는 research/brief.json에 저장됩니다. 실제 영상 프레임이나 오디오를 보았다고 주장하지 않고, 외부 제목·설명 안의 명령은 신뢰하지 않습니다. 훅·구조·템포의 추상 패턴만 제안하고 복제하면 안 되는 요소와 분석 한계를 함께 기록합니다.", "execution": { "taskSupport": "forbidden" - "name": "video_synthesize_research" + "name": "video_synthesize_research", + "title": "Video: Synthesize research" }
--- pinned/video_validate +++ observed/video_validate { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": false, + "readOnlyHint": true, + "title": "Video: Validate" + }, "description": "ffprobe로 완성된 영상의 길이·해상도·코덱·픽셀 포맷을 검사합니다. H.264와 yuv420p가 아니면 이슈로 표시합니다.", "execution": { "taskSupport": "forbidden" - "ffmpegPath": { - "description": "FFmpeg 절대경로를 주면 같은 폴더의 ffprobe를 사용", - "type": "string" - }, "filePath": { "description": "절대경로. 상대경로는 허용하지 않습니다.", "minLength": 1, - "name": "video_validate" + "name": "video_validate", + "title": "Video: Validate" }
+ tool added: youtube_get_analytics_report
+ tool added: youtube_get_channel
+ tool added: youtube_get_content_insights
--- pinned/youtube_get_video_status +++ observed/youtube_get_video_status { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true, + "title": "YouTube: Get video status" + }, "description": "내 YouTube 영상의 업로드 처리 상태와 현재 공개 상태를 조회합니다.", "execution": { "taskSupport": "forbidden" + "profile": { + "description": "영상 소유 채널의 Google 로그인 프로필", + "pattern": "^[a-z0-9][a-z0-9_-]{0,63}$", + "type": "string" + }, "videoId": { "description": "YouTube video ID", "maxLength": 64, - "name": "youtube_get_video_status" + "name": "youtube_get_video_status", + "title": "YouTube: Get video status" }
+ tool added: youtube_list_comment_replies
+ tool added: youtube_list_comments
+ tool added: youtube_list_videos
+ tool added: youtube_reply_comment
+ tool added: youtube_schedule_video
+ tool added: youtube_set_thumbnail
+ tool added: youtube_update_video_metadata
--- pinned/youtube_update_video_privacy +++ observed/youtube_update_video_privacy { + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false, + "title": "YouTube: Update video privacy" + }, "description": "내 YouTube 영상의 공개 상태를 변경하고 실제 반영 상태를 다시 조회합니다. public/unlisted 변경은 같은 턴의 명시 승인 후 confirmVisible=true가 필요합니다.", "execution": { "taskSupport": "forbidden" + "profile": { + "description": "영상 소유 채널의 Google 로그인 프로필", + "pattern": "^[a-z0-9][a-z0-9_-]{0,63}$", + "type": "string" + }, "videoId": { "description": "YouTube video ID", "maxLength": 64, - "name": "youtube_update_video_privacy" + "name": "youtube_update_video_privacy", + "title": "YouTube: Update video privacy" }
--- pinned/youtube_upload_video +++ observed/youtube_upload_video { - "description": "로컬 영상 파일을 현재 Google OAuth 계정의 YouTube 채널에 업로드합니다. 기본 공개 상태는 private이며 public/unlisted는 같은 턴의 명시 승인 후 confirmVisible=true가 필요합니다. 업로드 후 youtube_get_video_status로 처리 완료 여부와 실제 공개 상태를 확인하세요. 요청이 타임아웃되면 업로드가 뒤늦게 완료될 수 있으므로 YouTube Studio를 먼저 확인하고 중복 재시도하지 마세요. YouTube OAuth 권한이 없으면 mimi_seed_auth_start(domains=[\"youtube\"])로 증분 연결하세요.", + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false, + "title": "YouTube: Upload video" + }, + "description": "로컬 영상 파일을 선택한 Google 로그인 프로필의 채널에 업로드합니다. expectedChannelId를 실제 인증 채널과 대조한 후 전송합니다. 기본 공개 상태는 private이며 public/unlisted는 같은 턴의 명시 승인 후 confirmVisible=true가 필요합니다. 업로드 후 youtube_get_video_status로 처리 완료 여부와 실제 공개 상태를 확인하세요. 요청이 타임아웃되면 업로드가 뒤늦게 완료될 수 있으므로 YouTube Studio를 먼저 확인하고 중복 재시도하지 마세요. YouTube OAuth 권한이 없으면 mimi_seed_auth_start(domains=[\"youtube\"])로 증분 연결하세요.", "execution": { "taskSupport": "forbidden" }, + "expectedChannelId": { + "description": "업로드 대상 채널 ID. 인증된 채널과 다르면 업로드 중단.", + "pattern": "^UC[\\w-]{22}$", + "type": "string" + }, "filePath": { "description": "업로드할 .mp4/.mov/.webm 영상 절대경로", "minLength": 1, + "profile": { + "description": "Google 로그인 프로필. 지정한 프로필만 사용하며 기본 계정으로 대체하지 않습니다.", + "pattern": "^[a-z0-9][a-z0-9_-]{0,63}$", + "type": "string" + }, "shortsOnly": { "default": false, "description": "true면 세로/정사각형·180초 이하 쇼츠 규격을 강제", + "expectedChannelId", "filePath", "title" ], - "name": "youtube_upload_video" + "name": "youtube_upload_video", + "title": "YouTube: Upload video" }
tool removed: appstore_attach_latest_build
tool removed: playstore_update_latest_release_notes
Current tools
Show all 247 tool fingerprints
Watch this server yourself
If you run this server, put the proxy in front of it. It pins these exact fingerprints on first connect and stops the session if they move.
npx -y mcp-pin@0.2.3 -- <your @yoonion/mimi-seed-mcp command>
Or subscribe to this page's RSS feed to be told when it changes.
Badge
The badge states one fact about time and nothing else. It never claims a server is safe.
[](https://mcp-pin.gautamkhosla.com/servers/bee37f2e40e782c3.html)