@yoonion/mimi-seed-mcp 0.13.13 → 0.13.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/assets/agent-guide.md +34 -11
- package/dist/appstore/product-review.d.ts +5 -1
- package/dist/appstore/product-review.js +31 -3
- package/dist/appstore/tools.d.ts +41 -0
- package/dist/appstore/tools.js +62 -0
- package/dist/registers/appstore.js +55 -2
- package/package.json +1 -1
- package/tool-manifest.json +3 -1
package/README.md
CHANGED
|
@@ -78,8 +78,8 @@ export ANTHROPIC_API_KEY=sk-ant-...
|
|
|
78
78
|
|
|
79
79
|
| 영역 | 도구 수 | 주요 도구 |
|
|
80
80
|
|------|---------|-----------|
|
|
81
|
-
| App Store Connect |
|
|
82
|
-
| Google Play |
|
|
81
|
+
| App Store Connect | 41 | `appstore_submit_for_review` / `appstore_upload_screenshot` / `appstore_update_product_review_note` / `appstore_upload_product_review_screenshot` |
|
|
82
|
+
| Google Play | 32 | `playstore_submit_release` / `playstore_promote_release` / `playstore_replace_images` / `playstore_reply_review` / `playstore_verify_service_account` |
|
|
83
83
|
| Firebase | 20 | `firebase_create_project` / `firebase_create_android_app` / `firebase_get_android_config` / `firebase_create_ios_app` |
|
|
84
84
|
| AdMob | 7 | `admob_list_apps` / `admob_create_ad_unit` / `admob_get_today_earnings` / `admob_get_report` |
|
|
85
85
|
| CI/CD (GitHub Actions · GitLab) | 6 | `ci_trigger_build` / `ci_get_build_status` / `ci_list_workflows` / `ci_cancel_build` |
|
package/assets/agent-guide.md
CHANGED
|
@@ -16,7 +16,7 @@ and which actions are irreversible.
|
|
|
16
16
|
|
|
17
17
|
## 0. The one thing that trips every agent: deferred tools
|
|
18
18
|
|
|
19
|
-
Mimi Seed exposes **150+ MCP tools** across
|
|
19
|
+
Mimi Seed exposes **150+ MCP tools** across every store, cloud, CI, social, and video domain (full inventory:
|
|
20
20
|
[`docs/domain/tool-catalog.md`](domain/tool-catalog.md)). Harnesses that lazy-load large tool catalogs —
|
|
21
21
|
**Claude Code most notably** — register these tools as **deferred**: the tool *names*
|
|
22
22
|
are visible (in a system reminder), but the **input schemas are not loaded**. If you
|
|
@@ -42,20 +42,36 @@ tools directly — but the *call order* and *safety rules* below still apply.
|
|
|
42
42
|
|
|
43
43
|
### Ready-made `select:` batches
|
|
44
44
|
|
|
45
|
+
Every registered tool appears in at least one batch below (test-enforced), so a task you can name is a batch
|
|
46
|
+
you can paste. Pick the row for the job; batching two rows in one `select:` call is fine.
|
|
47
|
+
|
|
45
48
|
| Goal | `ToolSearch` query |
|
|
46
49
|
|------|--------------------|
|
|
47
50
|
| First contact / "what's connected?" | `select:mimi_seed_status,mimi_seed_auth_status,mimi_seed_auth_start,mimi_seed_remote_sync_credentials` |
|
|
48
|
-
|
|
|
49
|
-
| Play Store
|
|
50
|
-
|
|
|
51
|
-
|
|
|
52
|
-
|
|
|
51
|
+
| Release readiness (either store) | `select:release_status,playstore_check_submission_risks,appstore_check_submission_risks,screenshot_validate` |
|
|
52
|
+
| Play Store release | `select:playstore_get_app,playstore_list_tracks,playstore_update_release_notes,playstore_update_latest_release_notes,playstore_promote_release,playstore_submit_release,playstore_check_submission_risks,playstore_plan_release` |
|
|
53
|
+
| Play Store listing + images | `select:playstore_get_listing,playstore_update_listing,playstore_update_details,playstore_upload_image,playstore_list_images,playstore_replace_images,playstore_delete_all_images` |
|
|
54
|
+
| Play Store reviews + stats | `select:playstore_list_reviews,playstore_reply_review,playstore_get_statistics,generate_review_reply` |
|
|
55
|
+
| Play Store IAP / subscriptions | `select:playstore_list_products,playstore_list_inapp_products,playstore_list_subscriptions,playstore_create_onetime_product,playstore_create_subscription,playstore_update_product,playstore_update_product_listing,playstore_update_subscription_listing,playstore_update_product_state,playstore_delete_product` |
|
|
56
|
+
| App Store / TestFlight | `select:appstore_list_apps,appstore_verify_credentials,appstore_get_app,appstore_list_versions,appstore_create_version,appstore_get_metadata,appstore_update_whats_new,appstore_list_builds,appstore_attach_build,appstore_attach_latest_build,appstore_list_beta_groups,appstore_submit_for_review,appstore_check_submission_risks,appstore_plan_release` |
|
|
57
|
+
| App Store review submission (the bundle) | `select:appstore_list_review_submissions,appstore_add_version_to_review_submission,appstore_remove_review_submission_item,appstore_update_version_string,appstore_cancel_review` |
|
|
58
|
+
| App Store screenshots | `select:appstore_list_app_info_localizations,appstore_get_metadata,appstore_list_screenshots,appstore_upload_screenshot,appstore_delete_screenshot,appstore_delete_screenshot_set,screenshot_validate` |
|
|
59
|
+
| App Store app info + review notes | `select:appstore_get_app_info,appstore_update_app_info_localization,appstore_create_app_info_localization,appstore_update_localization,appstore_get_review_notes,appstore_update_review_notes` |
|
|
60
|
+
| App Store reviews | `select:appstore_list_reviews,appstore_reply_review,generate_review_reply` |
|
|
61
|
+
| App Store IAP (products + review metadata) | `select:appstore_list_products,appstore_create_inapp_purchase,appstore_create_subscription,appstore_update_product,appstore_list_product_localizations,appstore_update_product_localization,appstore_update_product_review_note,appstore_upload_product_review_screenshot,appstore_add_product_to_review,appstore_delete_product` |
|
|
53
62
|
| Release notes from commits | `select:generate_release_notes_from_commits,playstore_update_release_notes,appstore_update_whats_new` |
|
|
54
|
-
| Firebase setup | `select:firebase_list_projects,firebase_get_project,firebase_create_project,firebase_create_android_app,firebase_create_ios_app,firebase_get_android_config,firebase_enable_common_services` |
|
|
55
|
-
|
|
|
56
|
-
|
|
|
57
|
-
|
|
|
58
|
-
|
|
|
63
|
+
| Firebase setup | `select:firebase_list_projects,firebase_get_project,firebase_create_project,firebase_create_android_app,firebase_create_ios_app,firebase_get_android_config,firebase_get_ios_config,firebase_enable_common_services` |
|
|
64
|
+
| Firebase apps + services (incl. web) | `select:firebase_list_android_apps,firebase_list_ios_apps,firebase_list_web_apps,firebase_create_web_app,firebase_get_web_config,firebase_enable_service,firebase_list_enabled_services,firebase_delete_android_app,firebase_delete_ios_app,firebase_delete_web_app` |
|
|
65
|
+
| Analytics wiring (Firebase ↔ GA4 ↔ BigQuery) | `select:firebase_link_analytics,firebase_get_analytics_details,ga4_list_account_summaries,ga4_list_properties,ga4_create_property,ga4_list_data_streams,ga4_create_data_stream,ga4_plan_bigquery_link,ga4_create_bigquery_link,ga4_run_report` |
|
|
66
|
+
| BigQuery | `select:bigquery_auth_status,bigquery_list_datasets,bigquery_list_tables,bigquery_get_table_schema,bigquery_run_query` |
|
|
67
|
+
| AdMob | `select:admob_list_accounts,admob_list_apps,admob_create_app,admob_create_ad_unit,admob_list_ad_units,admob_get_today_earnings,admob_get_report` |
|
|
68
|
+
| Google Ads (UAC) | `select:googleads_config_status,googleads_save_config,googleads_list_accessible_customers,googleads_list_campaigns,googleads_get_campaign_report,googleads_get_uac_report` |
|
|
69
|
+
| Search Console | `select:gsc_list_sites,gsc_list_sitemaps,gsc_get_sitemap,gsc_submit_sitemap,gsc_inspect_url,gsc_search_analytics` |
|
|
70
|
+
| Social posting (Facebook / Instagram / Threads) | `select:facebook_current_config,facebook_save_config,facebook_list_pages,facebook_get_page,facebook_post_photo,facebook_post_multi_photo,instagram_save_config,instagram_get_account,instagram_post_image,instagram_post_carousel,threads_current_config,threads_save_config,threads_refresh_token,threads_get_account,threads_post,threads_post_carousel` |
|
|
71
|
+
| Jenkins credentials + jobs | `select:jenkins_status,jenkins_save_config,jenkins_list_credentials,jenkins_create_credential,jenkins_delete_credential,jenkins_upload_keystore,jenkins_upload_playstore_sa,jenkins_list_jobs,jenkins_get_job_config,jenkins_create_job,jenkins_update_job` |
|
|
72
|
+
| CI (GitHub/GitLab) | `select:ci_save_config,ci_list_workflows,ci_trigger_build,ci_get_build_status,ci_list_recent_builds,ci_cancel_build` |
|
|
73
|
+
| Android signing / keystore | `select:android_signing_setup,android_generate_keystore,jenkins_upload_keystore,jenkins_upload_playstore_sa` |
|
|
74
|
+
| Service account end-to-end | `select:iam_list_service_accounts,iam_create_service_account,iam_list_keys,iam_create_key,iam_add_iam_policy_binding,setup_playstore_connection,playstore_register_service_account,playstore_verify_service_account,playstore_list_service_accounts,playstore_delete_service_account` |
|
|
59
75
|
| Story → researched video | `select:video_plan_from_story,video_research_youtube,video_search_stock_assets,video_synthesize_research,video_download_stock_assets,video_generate_image,video_add_local_asset,video_build_timeline,video_render,video_job_status,video_validate` |
|
|
60
76
|
| YouTube upload / publish | `select:youtube_upload_video,youtube_get_video_status,youtube_update_video_privacy,mimi_seed_auth_start` |
|
|
61
77
|
|
|
@@ -156,7 +172,10 @@ per-domain inventory is [`docs/domain/tool-catalog.md`](domain/tool-catalog.md).
|
|
|
156
172
|
| **Jenkins** (credentials + jobs) | `jenkins_status` · `jenkins_save_config` · `jenkins_create_credential` · `jenkins_upload_keystore` · `jenkins_upload_playstore_sa` · `jenkins_create_job` · `jenkins_update_job` |
|
|
157
173
|
| **Google Cloud IAM** | `iam_create_service_account` · `iam_create_key` · `iam_add_iam_policy_binding` |
|
|
158
174
|
| **BigQuery** | `bigquery_run_query` · `bigquery_list_datasets` · `bigquery_get_table_schema` |
|
|
175
|
+
| **GA4** | `ga4_list_properties` · `ga4_create_property` · `ga4_create_data_stream` · `ga4_run_report` · `ga4_plan_bigquery_link` · `ga4_create_bigquery_link` |
|
|
176
|
+
| **Google Ads (UAC)** | `googleads_list_campaigns` · `googleads_get_uac_report` · `googleads_get_campaign_report` · `googleads_config_status` |
|
|
159
177
|
| **Search Console** | `gsc_inspect_url` · `gsc_search_analytics` · `gsc_submit_sitemap` |
|
|
178
|
+
| **Android signing** | `android_signing_setup` · `android_generate_keystore` · `jenkins_upload_playstore_sa` |
|
|
160
179
|
| **Facebook / Instagram / Threads** | `facebook_post_photo` · `instagram_post_carousel` · `threads_post` · `threads_refresh_token` |
|
|
161
180
|
| **Checks** | `playstore_check_submission_risks` · `appstore_check_submission_risks` · `screenshot_validate` · `release_status` |
|
|
162
181
|
| **AI / Auth** | `generate_release_notes_from_commits` · `generate_review_reply` · `mimi_seed_status` · `mimi_seed_auth_start` · `mimi_seed_auth_status` · `mimi_seed_remote_sync_credentials` |
|
|
@@ -183,6 +202,10 @@ per-domain inventory is [`docs/domain/tool-catalog.md`](domain/tool-catalog.md).
|
|
|
183
202
|
`playstore_update_release_notes` / `appstore_update_whats_new`.
|
|
184
203
|
|
|
185
204
|
### Story → researched video
|
|
205
|
+
For visual production, use the bundled `video-create-publish` skill. It requires an explicit typography system,
|
|
206
|
+
aspect-ratio-specific human-safe crops, video-native motion, an original-resolution frame review, and a saved
|
|
207
|
+
contact sheet; codec validation alone is not a quality pass.
|
|
208
|
+
|
|
186
209
|
1. `video_plan_from_story` — create the project and scene plan.
|
|
187
210
|
2. `video_research_youtube` — collect reference-only metadata; never treat a result as a render asset.
|
|
188
211
|
3. `video_search_stock_assets` — find licensed Pexels candidates.
|
|
@@ -12,12 +12,15 @@ export declare function updateProductReviewNote(args: {
|
|
|
12
12
|
}>;
|
|
13
13
|
/**
|
|
14
14
|
* 기존 IAP/구독 상품에 App Review 스크린샷을 reserve → upload → commit 한다.
|
|
15
|
-
* App Store Connect API는 상품당 심사용 스크린샷 하나를
|
|
15
|
+
* App Store Connect API는 상품당 심사용 스크린샷 하나를 허용한다 —
|
|
16
|
+
* 이미 있으면 409 `MEDIA_ASSET_CREATION_NOT_ALLOWED: Screenshot already exists` 다.
|
|
17
|
+
* 갈아끼우려면 replace: true (기존 것을 지우고 올린다).
|
|
16
18
|
*/
|
|
17
19
|
export declare function uploadProductReviewScreenshot(args: {
|
|
18
20
|
internalId: string;
|
|
19
21
|
productType: AppStoreProductType;
|
|
20
22
|
filePath: string;
|
|
23
|
+
replace?: boolean;
|
|
21
24
|
}): Promise<{
|
|
22
25
|
id: string;
|
|
23
26
|
internalId: string;
|
|
@@ -26,4 +29,5 @@ export declare function uploadProductReviewScreenshot(args: {
|
|
|
26
29
|
fileSize: number;
|
|
27
30
|
state?: string;
|
|
28
31
|
verified: boolean;
|
|
32
|
+
replacedId?: string;
|
|
29
33
|
}>;
|
|
@@ -70,12 +70,31 @@ async function uploadChunks(buffer, operations) {
|
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* 상품에 이미 붙어 있는 심사 스크린샷 id 를 찾는다. 없으면 null.
|
|
75
|
+
*
|
|
76
|
+
* 조회 경로가 상품 종류마다 다르다 — 구독은 v1, IAP 는 **v2** 다.
|
|
77
|
+
* v1 으로 IAP 를 조회하면 스크린샷이 있어도 404 가 나서 "없음"으로 오독하기 쉽다
|
|
78
|
+
* (2026-07-25 실측: 404 를 믿고 업로드했다가 "Screenshot already exists" 409).
|
|
79
|
+
*/
|
|
80
|
+
async function findExistingReviewScreenshotId(internalId, productType, authHeaders) {
|
|
81
|
+
const product = productResource(productType);
|
|
82
|
+
try {
|
|
83
|
+
const res = await apiRequest(product.base, `${product.path}/${internalId}/appStoreReviewScreenshot`, authHeaders, { method: 'GET' });
|
|
84
|
+
return res?.data?.id ?? null;
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
73
90
|
/**
|
|
74
91
|
* 기존 IAP/구독 상품에 App Review 스크린샷을 reserve → upload → commit 한다.
|
|
75
|
-
* App Store Connect API는 상품당 심사용 스크린샷 하나를
|
|
92
|
+
* App Store Connect API는 상품당 심사용 스크린샷 하나를 허용한다 —
|
|
93
|
+
* 이미 있으면 409 `MEDIA_ASSET_CREATION_NOT_ALLOWED: Screenshot already exists` 다.
|
|
94
|
+
* 갈아끼우려면 replace: true (기존 것을 지우고 올린다).
|
|
76
95
|
*/
|
|
77
96
|
export async function uploadProductReviewScreenshot(args) {
|
|
78
|
-
const { internalId, productType, filePath } = args;
|
|
97
|
+
const { internalId, productType, filePath, replace = false } = args;
|
|
79
98
|
if (!path.isAbsolute(filePath)) {
|
|
80
99
|
throw new Error(`절대 경로가 필요해: ${filePath}`);
|
|
81
100
|
}
|
|
@@ -94,6 +113,15 @@ export async function uploadProductReviewScreenshot(args) {
|
|
|
94
113
|
const checksum = crypto.createHash('md5').update(buffer).digest('hex');
|
|
95
114
|
const resource = reviewScreenshotResource(productType);
|
|
96
115
|
const authHeaders = await authHeadersOrThrow();
|
|
116
|
+
// 상품당 1장이라 새로 올리려면 기존 것을 먼저 지워야 한다.
|
|
117
|
+
let replacedId;
|
|
118
|
+
if (replace) {
|
|
119
|
+
const existing = await findExistingReviewScreenshotId(internalId, productType, authHeaders);
|
|
120
|
+
if (existing) {
|
|
121
|
+
await apiRequest(V1_BASE, `${resource.path}/${existing}`, authHeaders, { method: 'DELETE' });
|
|
122
|
+
replacedId = existing;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
97
125
|
const reserved = await apiRequest(V1_BASE, resource.path, authHeaders, {
|
|
98
126
|
method: 'POST',
|
|
99
127
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -148,5 +176,5 @@ export async function uploadProductReviewScreenshot(args) {
|
|
|
148
176
|
catch {
|
|
149
177
|
// commit 성공 후 확인 GET만 실패하면 재업로드를 유도하지 않는다.
|
|
150
178
|
}
|
|
151
|
-
return { id: screenshotId, internalId, productType, fileName, fileSize, state, verified };
|
|
179
|
+
return { id: screenshotId, internalId, productType, fileName, fileSize, state, verified, replacedId };
|
|
152
180
|
}
|
package/dist/appstore/tools.d.ts
CHANGED
|
@@ -40,6 +40,23 @@ export declare function createVersion(input: CreateVersionInput): Promise<{
|
|
|
40
40
|
releaseType: any;
|
|
41
41
|
createdDate: any;
|
|
42
42
|
}>;
|
|
43
|
+
/**
|
|
44
|
+
* 기존 버전 레코드의 versionString 을 바꾼다 (예: 2.0.5 → 2.0.6).
|
|
45
|
+
*
|
|
46
|
+
* 왜 필요한가: ASC 는 편집 가능한 버전이 이미 있으면 새 버전 생성을 거부한다
|
|
47
|
+
* 409 ENTITY_ERROR.RELATIONSHIP.INVALID "You cannot create a new version of the App in the current state"
|
|
48
|
+
* 그래서 거절/철회된 버전으로 다음 릴리스를 내보내려면 **같은 레코드의 이름을 올려야** 한다.
|
|
49
|
+
* 빌드는 CFBundleShortVersionString 이 일치하는 버전에만 붙으므로, 2.0.6 빌드를 올렸다면
|
|
50
|
+
* 버전 레코드도 2.0.6 이어야 attach 가 된다.
|
|
51
|
+
*
|
|
52
|
+
* 편집 가능한 상태(PREPARE_FOR_SUBMISSION / DEVELOPER_REJECTED / REJECTED 등)에서만 통한다.
|
|
53
|
+
*/
|
|
54
|
+
export declare function updateVersionString(versionId: string, versionString: string): Promise<{
|
|
55
|
+
versionId: string;
|
|
56
|
+
versionString: any;
|
|
57
|
+
state: any;
|
|
58
|
+
platform: any;
|
|
59
|
+
}>;
|
|
43
60
|
export declare function attachBuildToVersion(versionId: string, buildId: string): Promise<{
|
|
44
61
|
versionId: string;
|
|
45
62
|
buildId: string;
|
|
@@ -212,6 +229,30 @@ export declare function removeReviewSubmissionItem(itemId: string): Promise<{
|
|
|
212
229
|
state?: string;
|
|
213
230
|
removed: boolean;
|
|
214
231
|
}>;
|
|
232
|
+
/**
|
|
233
|
+
* 이미 존재하는 묶음에 앱 버전을 항목으로 끼워 넣는다.
|
|
234
|
+
*
|
|
235
|
+
* 앱 첫 심사에서 반드시 필요하다. 웹에서 상품을 담으면 **상품만 든 묶음**이 새로 생기는데,
|
|
236
|
+
* 그대로 제출하면 Apple 이 막는다:
|
|
237
|
+
* 409 ENTITY_ERROR.RELATIONSHIP.REQUIRED
|
|
238
|
+
* "must have an approved appStoreVersions ... or an appStoreVersions must be included
|
|
239
|
+
* in this review submission"
|
|
240
|
+
* 즉 상품 묶음에는 앱 버전이 함께 있어야 한다. reviewSubmissionItems 는 상품 관계는
|
|
241
|
+
* 거부하지만 **appStoreVersion 관계는 받는다** — 그래서 버전만 이쪽으로 옮기면 된다.
|
|
242
|
+
*
|
|
243
|
+
* 버전이 다른 묶음에 이미 물려 있으면 그 묶음을 먼저 정리해야 한다:
|
|
244
|
+
* - 미제출(READY_FOR_REVIEW) 묶음이면 appstore_remove_review_submission_item
|
|
245
|
+
* - 제출된(WAITING_FOR_REVIEW) 묶음이면 항목 제거가 막히므로 appstore_cancel_review 로 묶음째 취소
|
|
246
|
+
*/
|
|
247
|
+
export declare function addVersionToReviewSubmission(args: {
|
|
248
|
+
submissionId: string;
|
|
249
|
+
versionId: string;
|
|
250
|
+
}): Promise<{
|
|
251
|
+
itemId?: string;
|
|
252
|
+
submissionId: string;
|
|
253
|
+
versionId: string;
|
|
254
|
+
itemCount: number;
|
|
255
|
+
}>;
|
|
215
256
|
export declare function cancelVersionReview(versionId: string): Promise<{
|
|
216
257
|
submissionId: string;
|
|
217
258
|
previousState: string;
|
package/dist/appstore/tools.js
CHANGED
|
@@ -196,6 +196,33 @@ export async function createVersion(input) {
|
|
|
196
196
|
createdDate: created?.data?.attributes?.createdDate,
|
|
197
197
|
};
|
|
198
198
|
}
|
|
199
|
+
/**
|
|
200
|
+
* 기존 버전 레코드의 versionString 을 바꾼다 (예: 2.0.5 → 2.0.6).
|
|
201
|
+
*
|
|
202
|
+
* 왜 필요한가: ASC 는 편집 가능한 버전이 이미 있으면 새 버전 생성을 거부한다
|
|
203
|
+
* 409 ENTITY_ERROR.RELATIONSHIP.INVALID "You cannot create a new version of the App in the current state"
|
|
204
|
+
* 그래서 거절/철회된 버전으로 다음 릴리스를 내보내려면 **같은 레코드의 이름을 올려야** 한다.
|
|
205
|
+
* 빌드는 CFBundleShortVersionString 이 일치하는 버전에만 붙으므로, 2.0.6 빌드를 올렸다면
|
|
206
|
+
* 버전 레코드도 2.0.6 이어야 attach 가 된다.
|
|
207
|
+
*
|
|
208
|
+
* 편집 가능한 상태(PREPARE_FOR_SUBMISSION / DEVELOPER_REJECTED / REJECTED 등)에서만 통한다.
|
|
209
|
+
*/
|
|
210
|
+
export async function updateVersionString(versionId, versionString) {
|
|
211
|
+
const patched = await apiPatch(`/appStoreVersions/${versionId}`, {
|
|
212
|
+
data: {
|
|
213
|
+
type: 'appStoreVersions',
|
|
214
|
+
id: versionId,
|
|
215
|
+
attributes: { versionString },
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
const attrs = patched?.data?.attributes ?? {};
|
|
219
|
+
return {
|
|
220
|
+
versionId,
|
|
221
|
+
versionString: attrs.versionString ?? versionString,
|
|
222
|
+
state: attrs.appStoreState ?? attrs.appVersionState,
|
|
223
|
+
platform: attrs.platform,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
199
226
|
export async function attachBuildToVersion(versionId, buildId) {
|
|
200
227
|
// /relationships/build 엔드포인트는 204 No Content 반환
|
|
201
228
|
await apiPatch(`/appStoreVersions/${versionId}/relationships/build`, {
|
|
@@ -838,6 +865,41 @@ export async function removeReviewSubmissionItem(itemId) {
|
|
|
838
865
|
removed: patched?.data?.attributes?.removed ?? true,
|
|
839
866
|
};
|
|
840
867
|
}
|
|
868
|
+
/**
|
|
869
|
+
* 이미 존재하는 묶음에 앱 버전을 항목으로 끼워 넣는다.
|
|
870
|
+
*
|
|
871
|
+
* 앱 첫 심사에서 반드시 필요하다. 웹에서 상품을 담으면 **상품만 든 묶음**이 새로 생기는데,
|
|
872
|
+
* 그대로 제출하면 Apple 이 막는다:
|
|
873
|
+
* 409 ENTITY_ERROR.RELATIONSHIP.REQUIRED
|
|
874
|
+
* "must have an approved appStoreVersions ... or an appStoreVersions must be included
|
|
875
|
+
* in this review submission"
|
|
876
|
+
* 즉 상품 묶음에는 앱 버전이 함께 있어야 한다. reviewSubmissionItems 는 상품 관계는
|
|
877
|
+
* 거부하지만 **appStoreVersion 관계는 받는다** — 그래서 버전만 이쪽으로 옮기면 된다.
|
|
878
|
+
*
|
|
879
|
+
* 버전이 다른 묶음에 이미 물려 있으면 그 묶음을 먼저 정리해야 한다:
|
|
880
|
+
* - 미제출(READY_FOR_REVIEW) 묶음이면 appstore_remove_review_submission_item
|
|
881
|
+
* - 제출된(WAITING_FOR_REVIEW) 묶음이면 항목 제거가 막히므로 appstore_cancel_review 로 묶음째 취소
|
|
882
|
+
*/
|
|
883
|
+
export async function addVersionToReviewSubmission(args) {
|
|
884
|
+
const { submissionId, versionId } = args;
|
|
885
|
+
const created = await apiPost('/reviewSubmissionItems', {
|
|
886
|
+
data: {
|
|
887
|
+
type: 'reviewSubmissionItems',
|
|
888
|
+
relationships: {
|
|
889
|
+
reviewSubmission: { data: { type: 'reviewSubmissions', id: submissionId } },
|
|
890
|
+
appStoreVersion: { data: { type: 'appStoreVersions', id: versionId } },
|
|
891
|
+
},
|
|
892
|
+
},
|
|
893
|
+
});
|
|
894
|
+
// 제출 전에 몇 개가 들어있는지 보여준다 — 첫 심사에서 "상품이 빠졌는지"를 눈으로 확인해야 한다.
|
|
895
|
+
const items = await apiGet(`/reviewSubmissions/${submissionId}/items`, { limit: '50' }).catch(() => null);
|
|
896
|
+
return {
|
|
897
|
+
itemId: created?.data?.id,
|
|
898
|
+
submissionId,
|
|
899
|
+
versionId,
|
|
900
|
+
itemCount: (items?.data ?? []).length,
|
|
901
|
+
};
|
|
902
|
+
}
|
|
841
903
|
/**
|
|
842
904
|
* 버전을 물고 있는 낡은 묶음(UNRESOLVED_ISSUES)에서 해당 버전 항목을 removed=true 로
|
|
843
905
|
* 풀어준다. 항목이 풀리면 Apple 이 옛 묶음을 COMPLETE 로 정리하고, 종종 새
|
|
@@ -554,12 +554,16 @@ export function registerAppstoreTools(server) {
|
|
|
554
554
|
}],
|
|
555
555
|
};
|
|
556
556
|
});
|
|
557
|
-
server.tool('appstore_upload_product_review_screenshot',
|
|
557
|
+
server.tool('appstore_upload_product_review_screenshot', [
|
|
558
|
+
'기존 App Store IAP/구독 상품의 심사용 스크린샷을 reserve → upload → commit. 상품당 1장, 절대 파일 경로 필요.',
|
|
559
|
+
'이미 있으면 409 "Screenshot already exists" — 갈아끼우려면 replace: true (기존 것을 지우고 올린다).',
|
|
560
|
+
].join(' '), {
|
|
558
561
|
appId: z.string().describe('App Store 앱 ID (숫자형, appstore_list_apps 결과)'),
|
|
559
562
|
productId: z.string().describe('상품 ID (appstore_list_products 결과)'),
|
|
560
563
|
productType: z.enum(['subscription', 'consumable', 'non_consumable']).describe('상품 유형'),
|
|
561
564
|
filePath: z.string().describe('업로드할 PNG/JPG의 절대 파일 경로'),
|
|
562
|
-
|
|
565
|
+
replace: z.boolean().optional().describe('이미 스크린샷이 있으면 지우고 새로 올린다 (기본 false)'),
|
|
566
|
+
}, async ({ appId, productId, productType, filePath, replace }) => {
|
|
563
567
|
const creds = requireAppStoreCreds();
|
|
564
568
|
const products = await listAppleProducts({
|
|
565
569
|
appId, keyId: creds.keyId, issuerId: creds.issuerId, privateKey: creds.privateKey,
|
|
@@ -572,6 +576,7 @@ export function registerAppstoreTools(server) {
|
|
|
572
576
|
internalId: product.internalId,
|
|
573
577
|
productType,
|
|
574
578
|
filePath,
|
|
579
|
+
replace,
|
|
575
580
|
});
|
|
576
581
|
return {
|
|
577
582
|
content: [{
|
|
@@ -581,6 +586,7 @@ export function registerAppstoreTools(server) {
|
|
|
581
586
|
`productId: ${productId}`,
|
|
582
587
|
`internalId: ${result.internalId}`,
|
|
583
588
|
`screenshotId: ${result.id}`,
|
|
589
|
+
result.replacedId ? `교체됨 (이전 screenshotId: ${result.replacedId})` : '',
|
|
584
590
|
`file: ${result.fileName} (${result.fileSize} bytes)`,
|
|
585
591
|
result.state ? `state: ${result.state}` : '',
|
|
586
592
|
result.verified ? '✓ commit 후 조회 확인' : '⚠ commit은 성공했지만 후속 조회는 확인하지 못함',
|
|
@@ -689,6 +695,53 @@ export function registerAppstoreTools(server) {
|
|
|
689
695
|
}],
|
|
690
696
|
};
|
|
691
697
|
});
|
|
698
|
+
server.tool('appstore_add_version_to_review_submission', '이미 존재하는 심사 묶음에 앱 버전을 항목으로 추가한다 (POST /reviewSubmissionItems). ' +
|
|
699
|
+
'⚠️ 앱 첫 심사 필수 절차 — 웹에서 IAP/구독을 담으면 "상품만 든 묶음"이 새로 생기는데, ' +
|
|
700
|
+
'그대로 제출하면 409 "an appStoreVersions must be included in this review submission" 로 막힌다. ' +
|
|
701
|
+
'reviewSubmissionItems 는 상품 관계는 거부하지만 appStoreVersion 관계는 받으므로, 버전을 이 묶음으로 옮기면 된다. ' +
|
|
702
|
+
'버전이 다른 묶음에 물려 있으면 먼저 풀 것: 미제출 묶음이면 appstore_remove_review_submission_item, ' +
|
|
703
|
+
'제출된 묶음이면 항목 제거가 막히므로 appstore_cancel_review 로 묶음째 취소. ' +
|
|
704
|
+
'추가 후 appstore_submit_for_review 로 제출하면 버전+상품이 한 묶음으로 나간다.', {
|
|
705
|
+
submissionId: z.string().describe('대상 reviewSubmission ID (appstore_list_review_submissions 결과)'),
|
|
706
|
+
versionId: z.string().describe('추가할 App Store 버전 ID (appstore_list_versions 결과)'),
|
|
707
|
+
}, async ({ submissionId, versionId }) => {
|
|
708
|
+
const result = await appstore.addVersionToReviewSubmission({ submissionId, versionId });
|
|
709
|
+
return {
|
|
710
|
+
content: [{
|
|
711
|
+
type: 'text',
|
|
712
|
+
text: [
|
|
713
|
+
'✓ 묶음에 앱 버전 추가됨',
|
|
714
|
+
`submissionId: ${result.submissionId}`,
|
|
715
|
+
`versionId: ${result.versionId}`,
|
|
716
|
+
result.itemId ? `itemId: ${result.itemId}` : '',
|
|
717
|
+
`현재 묶음 항목 수: ${result.itemCount}개`,
|
|
718
|
+
'제출 전 항목 수를 확인할 것 — 첫 심사라면 상품들이 함께 들어 있어야 한다.',
|
|
719
|
+
].filter(Boolean).join('\n'),
|
|
720
|
+
}],
|
|
721
|
+
};
|
|
722
|
+
});
|
|
723
|
+
server.tool('appstore_update_version_string', '기존 App Store 버전 레코드의 versionString 을 변경 (예: 2.0.5 → 2.0.6). ' +
|
|
724
|
+
'⚠️ 편집 가능한 버전이 이미 있으면 appstore_create_version 이 409 "cannot create a new version in the current state" 로 막힌다 — ' +
|
|
725
|
+
'거절/철회된 버전으로 다음 릴리스를 내보내려면 새로 만들지 말고 이 도구로 **같은 레코드의 이름을 올린다**. ' +
|
|
726
|
+
'빌드는 CFBundleShortVersionString 이 같은 버전에만 붙으므로, 새 버전의 빌드를 attach 하려면 먼저 이걸 맞춰야 한다. ' +
|
|
727
|
+
'PREPARE_FOR_SUBMISSION / DEVELOPER_REJECTED 등 편집 가능 상태에서만 통한다.', {
|
|
728
|
+
versionId: z.string().describe('App Store 버전 ID (appstore_list_versions 결과)'),
|
|
729
|
+
versionString: z.string().describe('새 버전 문자열 (예: "2.0.6")'),
|
|
730
|
+
}, async ({ versionId, versionString }) => {
|
|
731
|
+
const result = await appstore.updateVersionString(versionId, versionString);
|
|
732
|
+
return {
|
|
733
|
+
content: [{
|
|
734
|
+
type: 'text',
|
|
735
|
+
text: [
|
|
736
|
+
'✓ 버전 문자열 변경 완료',
|
|
737
|
+
`versionId: ${result.versionId}`,
|
|
738
|
+
`versionString: ${result.versionString}`,
|
|
739
|
+
result.state ? `state: ${result.state}` : '',
|
|
740
|
+
'이제 같은 버전의 빌드를 attach 할 수 있다 (appstore_attach_latest_build).',
|
|
741
|
+
].filter(Boolean).join('\n'),
|
|
742
|
+
}],
|
|
743
|
+
};
|
|
744
|
+
});
|
|
692
745
|
server.tool('appstore_update_product', 'App Store IAP 상품의 reference name 변경. productId / 유형은 변경 불가. ' +
|
|
693
746
|
'스토어에 보이는 표시 이름·설명은 appstore_update_product_localization 을 쓴다.', {
|
|
694
747
|
appId: z.string().optional().describe('App Store 앱 ID'),
|
package/package.json
CHANGED
package/tool-manifest.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$comment": "등록된 MCP 도구 + 도메인 메타데이터(label·credential·summary)의 SSOT. src/__tests__/tool-manifest.test.ts 가 실제 서버 등록 목록과 diff 하고 메타데이터 정합성을 검사한다. 도구 추가/삭제/개명 시 이 파일을 함께 갱신할 것 — 산문 문서에는 정확한 개수를 쓰지 말고 이 파일을 가리킬 것. mimi-seed://tools/catalog 리소스가 이 파일을 그대로 서빙한다.",
|
|
3
|
-
"total":
|
|
3
|
+
"total": 189,
|
|
4
4
|
"domains": {
|
|
5
5
|
"admob": {
|
|
6
6
|
"label": "AdMob",
|
|
@@ -78,6 +78,8 @@
|
|
|
78
78
|
"appstore_submit_for_review",
|
|
79
79
|
"appstore_list_review_submissions",
|
|
80
80
|
"appstore_remove_review_submission_item",
|
|
81
|
+
"appstore_add_version_to_review_submission",
|
|
82
|
+
"appstore_update_version_string",
|
|
81
83
|
"appstore_cancel_review"
|
|
82
84
|
]
|
|
83
85
|
},
|