@yoonion/mimi-seed-mcp 0.10.2 → 0.11.0

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 CHANGED
@@ -108,6 +108,7 @@ MCP 클라이언트(Claude Code, Codex 등)에서 슬래시 커맨드로 바로
108
108
 
109
109
  | 커맨드 | 설명 |
110
110
  |--------|------|
111
+ | `/mimi-seed:getting-started` | 처음 사용자 온보딩 — 연결 스캔 → 능력 투어 → 첫 읽기 전용 액션 |
111
112
  | `/mimi-seed:deploy` | 블로커 점검 → 릴리즈 노트 생성 → 스토어 적용을 한 번에 |
112
113
  | `/mimi-seed:health` | 인증 상태 + 앱 출시 준비도 빠른 요약 |
113
114
  | `/mimi-seed:review-inbox` | 미답변 리뷰 조회 → AI 답변 초안 생성 |
@@ -117,7 +118,8 @@ MCP 클라이언트(Claude Code, Codex 등)에서 슬래시 커맨드로 바로
117
118
  | URI | 설명 |
118
119
  |-----|------|
119
120
  | `mimi-seed://auth/status` | Google OAuth 토큰 상태 (JSON) |
120
- | `mimi-seed://agent/guide` | 에이전트 역할 정의출시 워크플로우·주의사항 (Markdown) |
121
+ | `mimi-seed://agent/guide` | 에이전트 운영 규약 전문 deferred 도구 로딩·`select:` 배치·호출 순서·안전수칙 (Markdown) |
122
+ | `mimi-seed://tools/catalog` | 도메인별 전체 도구 목록 + 필요 자격증명 + 요약 (JSON) — "뭘 할 수 있어?"의 런타임 답 |
121
123
 
122
124
  ---
123
125
 
@@ -0,0 +1,239 @@
1
+ # Agent Guide — Driving Mimi Seed from an AI
2
+
3
+ > How an AI coding agent (Claude Code, Codex, Cursor, …) should call the Mimi Seed
4
+ > MCP tools correctly. If you are an agent and a user asks you to do app-store /
5
+ > Firebase / AdMob / CI work through `@yoonion/mimi-seed-mcp`, read this first.
6
+
7
+ The human-facing install + feature docs live in [`README.md`](../README.md). This file
8
+ is the **operational contract for agents**: how tools load, what order to call them in,
9
+ and which actions are irreversible.
10
+
11
+ > **Building or modifying the SDK itself?** The structural companion to this guide — architecture, the full tool
12
+ > catalog, the auth/credential model, and pitfalls — lives in the domain ontology under
13
+ > [`docs/domain/`](domain/_index.md). This guide is *how to call* the tools; the ontology is *how they're built*.
14
+
15
+ ---
16
+
17
+ ## 0. The one thing that trips every agent: deferred tools
18
+
19
+ Mimi Seed exposes **150+ MCP tools** across 18 domains (full inventory:
20
+ [`docs/domain/tool-catalog.md`](domain/tool-catalog.md)). Harnesses that lazy-load large tool catalogs —
21
+ **Claude Code most notably** — register these tools as **deferred**: the tool *names*
22
+ are visible (in a system reminder), but the **input schemas are not loaded**. If you
23
+ call a deferred tool directly, it fails with `InputValidationError` ("schema not
24
+ loaded"), and it is easy to wrongly conclude "this tool doesn't exist."
25
+
26
+ **Always load the schema before the first call.** In Claude Code:
27
+
28
+ ```
29
+ ToolSearch(query="select:<tool_name>[,<tool_name>...]")
30
+ ```
31
+
32
+ - Batch every tool you expect to use in one `select:` call — schemas stay loaded for
33
+ the rest of the session.
34
+ - If `select:` returns no match, fall back to a keyword search
35
+ (`ToolSearch(query="playstore release promote")`) — exact names sometimes differ.
36
+ - Only if a tool is absent from the deferred list **and** unsearchable is it truly
37
+ unregistered. Then check the MCP server is connected (see §2), do **not** silently
38
+ pivot to raw `curl` / `fastlane`.
39
+
40
+ Other harnesses (Codex with the bundled plugin, Claude Desktop) typically expose the
41
+ tools directly — but the *call order* and *safety rules* below still apply.
42
+
43
+ ### Ready-made `select:` batches
44
+
45
+ | Goal | `ToolSearch` query |
46
+ |------|--------------------|
47
+ | First contact / "what's connected?" | `select:mimi_seed_status,mimi_seed_auth_status,mimi_seed_auth_start,mimi_seed_remote_sync_credentials` |
48
+ | Play Store release | `select:playstore_get_app,playstore_list_tracks,playstore_update_latest_release_notes,playstore_promote_release,playstore_submit_release,playstore_check_submission_risks,playstore_plan_release` |
49
+ | Play Store listing + images | `select:playstore_get_listing,playstore_update_listing,playstore_upload_image,playstore_list_images,playstore_replace_images,playstore_delete_all_images` |
50
+ | App Store / TestFlight | `select:appstore_list_apps,appstore_list_versions,appstore_create_version,appstore_get_metadata,appstore_update_whats_new,appstore_list_builds,appstore_attach_latest_build,appstore_submit_for_review,appstore_check_submission_risks,appstore_plan_release` |
51
+ | App Store screenshots | `select:appstore_list_app_info_localizations,appstore_get_metadata,appstore_list_screenshots,appstore_upload_screenshot,appstore_delete_screenshot_set,screenshot_validate` |
52
+ | App Store IAP review metadata | `select:appstore_list_apps,appstore_list_products,appstore_update_product_review_note,appstore_upload_product_review_screenshot` |
53
+ | 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
+ | AdMob | `select:admob_list_accounts,admob_list_apps,admob_create_ad_unit,admob_list_ad_units,admob_get_today_earnings,admob_get_report` |
56
+ | Jenkins credentials + jobs | `select:jenkins_status,jenkins_save_config,jenkins_list_credentials,jenkins_create_credential,jenkins_upload_keystore,jenkins_upload_playstore_sa,jenkins_list_jobs,jenkins_get_job_config,jenkins_create_job,jenkins_update_job` |
57
+ | CI (GitHub/GitLab) | `select:ci_save_config,ci_list_workflows,ci_trigger_build,ci_get_build_status,ci_list_recent_builds` |
58
+ | Service account end-to-end | `select:iam_create_service_account,iam_create_key,iam_add_iam_policy_binding,playstore_register_service_account,playstore_verify_service_account` |
59
+
60
+ ---
61
+
62
+ ## 1. Always start with `mimi_seed_status`
63
+
64
+ Before any task, call **`mimi_seed_status`** — the setup doctor. It scans your service
65
+ credentials (Google OAuth · Play SA · App Store · Jenkins · CI · Google Ads · Facebook · Instagram ·
66
+ Threads · BigQuery) and returns a ✅/❌ report plus the exact next tool to call for anything
67
+ missing. This avoids a late `401`/`403` deep into a workflow.
68
+
69
+ > If the repo has a **`.mimi-seed.json`** manifest at its root, `mimi_seed_status` (and
70
+ > `mimi-seed doctor`) additionally report **which project-required services this teammate is
71
+ > missing** + the precise fix command — use that section to onboard a new teammate.
72
+ > **BigQuery** can be satisfied per-machine (`mimi-seed-bigquery-auth`) **or** workspace-wide:
73
+ > a workspace admin registers a shared service account once and every member queries via the
74
+ > **Remote MCP** with no personal key (`register_integration(provider="bigquery", …)`).
75
+
76
+ If auth is missing or expired, the shortest path for a human is **`mimi-seed setup`** — one guided pass over
77
+ every credential, which also tells them where to obtain each token
78
+ ([`credentials.md`](credentials.md)). Per-credential fixes:
79
+
80
+ | Service | Fix |
81
+ |---------|-----|
82
+ | Google (Firebase/AdMob/Play/Ads/GSC/GA4/IAM/BigQuery) | tool `mimi_seed_auth_start` → give the user the OAuth URL, **or** `mimi-seed auth login` |
83
+ | App Store Connect | `mimi-seed auth appstore` → verify with `appstore_verify_credentials` |
84
+ | Play service account | `mimi-seed auth playstore`, or register per-package with `playstore_register_service_account`. **Optional** — the OAuth token carries `androidpublisher`, so this is only needed for headless/CI |
85
+ | BigQuery | `mimi-seed auth bigquery` (optional — OAuth works too) |
86
+ | Jenkins | `mimi-seed auth jenkins` (probes the server before saving) |
87
+ | GitHub / GitLab CI | `mimi-seed auth ci` |
88
+ | Google Ads | `mimi-seed auth googleads` — needs the `adwords` OAuth scope; an old token may need `mimi-seed auth login --force` |
89
+ | Facebook / Instagram / Threads | `mimi-seed auth facebook` / `mimi-seed auth instagram` / `mimi-seed auth threads` |
90
+
91
+ `mimi-seed auth meta` opens the combined social setup entry point when the user wants to review or reconnect
92
+ all three Meta platforms in one pass.
93
+
94
+ Each `mimi-seed auth <cred>` wraps the matching `npx -y @yoonion/mimi-seed-mcp mimi-seed-*-auth` binary, so
95
+ either form works.
96
+
97
+ For Facebook, Instagram, and Threads, `mimi-seed setup` reads the saved expiry estimate. Expired tokens and
98
+ tokens with seven days or less remaining are automatically put back into the setup plan. A live Meta rejection
99
+ (including OAuth code 190) returns the exact `mimi-seed auth <platform>` recovery command instead of a raw error.
100
+ For an unexpired Threads long-lived token, `threads_refresh_token` (also the default path in `mimi-seed auth
101
+ threads`) refreshes it without asking the user to paste a replacement. Expired or revoked tokens still require a
102
+ new authorization.
103
+
104
+ ---
105
+
106
+ ## 2. Auth & credential model
107
+
108
+ Credentials live under `~/.mimi-seed/` (legacy `~/.preseed/` is still read):
109
+
110
+ | File | Used for |
111
+ |------|----------|
112
+ | `tokens.json` | Google OAuth (Firebase, AdMob, Play Developer API, IAM, BigQuery) |
113
+ | `appstore.json` | App Store Connect API key (JWT) |
114
+ | `play-service-accounts/<packageName>.json` | **per-package** Play service account |
115
+ | `play-service-account.json` | default/legacy Play SA (fallback when no per-package match) |
116
+ | `bigquery-service-account.json` | BigQuery SA (exempt from Workspace reauth; OAuth is the fallback) |
117
+ | `jenkins.json`, `ci.json` | Jenkins / GitHub-GitLab CI connection |
118
+ | `google-ads.json` | Google Ads developer token + customer id |
119
+ | `facebook.json`, `instagram.json`, `threads.json` | Page / account access tokens for the social post tools (Threads is a separate Meta account/token) |
120
+
121
+ Notes that matter in practice:
122
+
123
+ - **Per-package Play SA wins over the default.** Different apps can use SAs from
124
+ different GCP projects. `playstore_list_service_accounts` shows the mapping.
125
+ - The Play SA's **GCP project must have the Android Publisher API enabled**, or every
126
+ `playstore_*` call returns `403`.
127
+ - AI features (`generate_release_notes_from_commits`, `generate_review_reply`) need
128
+ `ANTHROPIC_API_KEY` in the environment.
129
+
130
+ ---
131
+
132
+ ## 3. Tool catalog (by domain)
133
+
134
+ Full schemas load on demand via `ToolSearch`. These are representative tools, not a full list — the exact
135
+ per-domain inventory is [`docs/domain/tool-catalog.md`](domain/tool-catalog.md).
136
+
137
+ | Domain | Representative tools |
138
+ |--------|----------------------|
139
+ | **Google Play** | `playstore_get_app` · `playstore_get_listing` · `playstore_update_listing` · `playstore_list_tracks` · `playstore_update_latest_release_notes` · `playstore_promote_release` · `playstore_submit_release` · `playstore_upload_image` · `playstore_replace_images` · `playstore_check_submission_risks` · `playstore_get_statistics` · `playstore_reply_review` · `playstore_register_service_account` |
140
+ | **App Store Connect** | `appstore_list_apps` · `appstore_list_versions` · `appstore_create_version` · `appstore_update_whats_new` · `appstore_update_localization` · `appstore_list_builds` · `appstore_attach_latest_build` · `appstore_upload_screenshot` · `appstore_submit_for_review` · `appstore_cancel_review` · `appstore_list_beta_groups` · `appstore_reply_review` |
141
+ | **Firebase** | `firebase_create_project` · `firebase_create_android_app` · `firebase_create_ios_app` · `firebase_get_android_config` · `firebase_enable_service` · `firebase_enable_common_services` · `firebase_list_*_apps` |
142
+ | **AdMob** | `admob_create_app` · `admob_create_ad_unit` · `admob_list_ad_units` · `admob_get_today_earnings` · `admob_get_report` |
143
+ | **CI/CD** | `ci_trigger_build` · `ci_get_build_status` · `ci_list_workflows` (**GitHub Actions / GitLab only**) |
144
+ | **Jenkins** (credentials + jobs) | `jenkins_status` · `jenkins_save_config` · `jenkins_create_credential` · `jenkins_upload_keystore` · `jenkins_upload_playstore_sa` · `jenkins_create_job` · `jenkins_update_job` |
145
+ | **Google Cloud IAM** | `iam_create_service_account` · `iam_create_key` · `iam_add_iam_policy_binding` |
146
+ | **BigQuery** | `bigquery_run_query` · `bigquery_list_datasets` · `bigquery_get_table_schema` |
147
+ | **Search Console** | `gsc_inspect_url` · `gsc_search_analytics` · `gsc_submit_sitemap` |
148
+ | **Facebook / Instagram / Threads** | `facebook_post_photo` · `instagram_post_carousel` · `threads_post` · `threads_refresh_token` |
149
+ | **Checks** | `playstore_check_submission_risks` · `appstore_check_submission_risks` · `screenshot_validate` · `release_status` |
150
+ | **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` |
151
+
152
+ ---
153
+
154
+ ## 4. Workflows (call sequences)
155
+
156
+ ### Play Store release / promote
157
+ 1. `playstore_list_tracks` — see current track/version state.
158
+ 2. `playstore_check_submission_risks` (or `playstore_plan_release`) — surface blockers.
159
+ 3. Write missing listing/notes (`playstore_update_listing`, `playstore_update_latest_release_notes`, `playstore_upload_image`).
160
+ 4. `playstore_promote_release` / `playstore_submit_release` — **confirm first** (see §5).
161
+
162
+ ### App Store TestFlight → review
163
+ 1. `appstore_list_apps` → `appstore_list_versions` (or `appstore_create_version`).
164
+ 2. `appstore_list_builds` → `appstore_attach_latest_build` (only `processingState=VALID`).
165
+ 3. `appstore_update_whats_new`, screenshots if needed.
166
+ 4. `appstore_check_submission_risks` → `appstore_submit_for_review` — **confirm first**.
167
+
168
+ ### Release notes from git
169
+ `generate_release_notes_from_commits` (pass commit array + locales) → review with user →
170
+ `playstore_update_release_notes` / `appstore_update_whats_new`.
171
+
172
+ > **Mimi Seed does not compile app binaries.** It manages metadata, store releases, and
173
+ > CI/Jenkins *credentials and job definitions* — not Xcode/Gradle builds. To produce an
174
+ > `.ipa`/`.aab`, use EAS, Xcode, or a CI/Jenkins job. There is **no `jenkins_trigger_build`
175
+ > tool**; trigger a Jenkins job via its REST API and use the `jenkins_*` tools for
176
+ > credentials and job configs.
177
+
178
+ ---
179
+
180
+ ## 5. Safety — irreversible actions need explicit confirmation
181
+
182
+ Never run these without the user's go-ahead in the same turn:
183
+
184
+ | Action | Why |
185
+ |--------|-----|
186
+ | `playstore_submit_release` / `playstore_promote_release` with `status=completed` | Starts Google review / full rollout. Near-irreversible. |
187
+ | `appstore_submit_for_review` | Submits to Apple review. |
188
+ | `appstore_delete_screenshot_set`, `playstore_delete_all_images` | Deletes assets. |
189
+ | `playstore_delete_product`, `jenkins_delete_credential`, `firebase_delete_*_app` | Destructive. |
190
+
191
+ General rules:
192
+ - Run `*_check_submission_risks` / `*_plan_release` **before** submitting, and show
193
+ blockers to the user as a checklist first.
194
+ - Pass file paths as **absolute paths**; never load image bytes into the conversation.
195
+ - Prefer `status=draft` while iterating; flip to `completed` only on explicit request.
196
+
197
+ ---
198
+
199
+ ## 6. Known gotchas (learned the hard way)
200
+
201
+ - **Draft-app track constraint (Play).** Until an app has its first non-internal
202
+ publish, only the **`internal`** track can be `completed`. `alpha`/`beta`/`production`
203
+ reject anything but `draft` → error: *"Only releases with status draft may be created
204
+ on draft app."* Closed/open testing also needs the **App Content** declarations
205
+ (content rating, data safety, target audience) which are **Console-only** — the API
206
+ cannot set them.
207
+ - **A `403` on one write but not another is usually NOT a permissions gap.** Every
208
+ `playstore_*` write resolves the same credential (`requirePlayStoreAuth`), so if
209
+ `playstore_upload_image` succeeds but `playstore_update_listing` returns `403`, the
210
+ account's permissions are fine. Read the **raw Google reason** surfaced in the error
211
+ (app state, policy, or an operation-specific restriction) instead of blindly
212
+ "granting permission" — the friendly 403 message now includes that reason.
213
+ - **Play edits overwrite un-published Console changes.** Committing *any* Play
214
+ Developer API edit (image upload, listing update, release) discards listing/release
215
+ changes you saved-but-didn't-publish in the Play Console UI. Google's own docs warn
216
+ against editing the same app with both tools at once. Do all listing writes via the
217
+ API, or finish & publish your Console edits first — never interleave them.
218
+ - **`ci_*` is GitHub/GitLab only.** It does not trigger Jenkins builds.
219
+ - **Reward/cash-out apps** are a sensitive Play category — flag policy implications to
220
+ the user, but it does not block test-track distribution.
221
+
222
+ ---
223
+
224
+ ## 7. Slash commands & MCP resources
225
+
226
+ Available in any MCP client as native slash commands:
227
+
228
+ - `/mimi-seed:getting-started` — first-run onboarding: status scan → capability tour → first read-only action
229
+ - `/mimi-seed:deploy` — blockers → release notes → apply to stores
230
+ - `/mimi-seed:health` — auth status + readiness summary
231
+ - `/mimi-seed:review-inbox` — fetch unanswered reviews → draft replies
232
+
233
+ MCP resources: `mimi-seed://auth/status` (live token state) · `mimi-seed://agent/guide`
234
+ (this guide, served over MCP) · `mimi-seed://tools/catalog` (the full tool inventory by
235
+ domain, with the credential each domain needs — read it to answer "what can Mimi Seed do?").
236
+
237
+ ---
238
+
239
+ _Keep this guide in sync with `README.md`'s tool list and the `skills/` directory._
@@ -66,6 +66,23 @@ export async function fetchUserId(accessToken) {
66
66
  }
67
67
  return id;
68
68
  }
69
+ // 이미지/캐러셀 컨테이너는 Meta 서버 처리가 끝난 뒤에만 publish 할 수 있다.
70
+ // 완료 전에 media_publish 를 호출하면 code 9007/2207027 이 반환된다.
71
+ async function waitForContainer(cfg, containerId) {
72
+ const MAX_ATTEMPTS = 20;
73
+ const INTERVAL_MS = 3000; // 최대 ~60초 대기
74
+ for (let i = 0; i < MAX_ATTEMPTS; i++) {
75
+ const { status_code, status } = await igFetch(cfg.accessToken, `/${containerId}`, { fields: 'status_code,status', access_token: cfg.accessToken });
76
+ const current = status_code ?? status;
77
+ if (current === 'FINISHED')
78
+ return;
79
+ if (current === 'ERROR' || current === 'EXPIRED') {
80
+ throw new Error(`Instagram 미디어 처리 실패 (${current}).`);
81
+ }
82
+ await new Promise((resolve) => setTimeout(resolve, INTERVAL_MS));
83
+ }
84
+ throw new Error('Instagram 미디어 처리 대기 시간 초과 (60초). 잠시 후 다시 시도하세요.');
85
+ }
69
86
  async function fetchPermalink(cfg, mediaId) {
70
87
  try {
71
88
  const meta = await igFetch(cfg.accessToken, `/${mediaId}`, { fields: 'permalink', access_token: cfg.accessToken });
@@ -95,6 +112,8 @@ export async function postCarousel(cfg, imageUrls, caption) {
95
112
  const child = await igFetch(cfg.accessToken, `/${cfg.userId}/media`, { image_url: url, is_carousel_item: 'true', access_token: cfg.accessToken }, 'POST');
96
113
  childIds.push(child.id);
97
114
  }
115
+ for (const childId of childIds)
116
+ await waitForContainer(cfg, childId);
98
117
  // Step 2: carousel container 생성
99
118
  const carousel = await igFetch(cfg.accessToken, `/${cfg.userId}/media`, {
100
119
  media_type: 'CAROUSEL',
@@ -102,6 +121,7 @@ export async function postCarousel(cfg, imageUrls, caption) {
102
121
  caption,
103
122
  access_token: cfg.accessToken,
104
123
  }, 'POST');
124
+ await waitForContainer(cfg, carousel.id);
105
125
  // Step 3: publish
106
126
  const published = await igFetch(cfg.accessToken, `/${cfg.userId}/media_publish`, { creation_id: carousel.id, access_token: cfg.accessToken }, 'POST');
107
127
  return {
package/dist/prompts.js CHANGED
@@ -1,5 +1,24 @@
1
1
  import { z } from 'zod';
2
2
  export function registerPrompts(server) {
3
+ server.prompt('getting-started', '처음 사용자 온보딩 — 연결 스캔 → 뭘 할 수 있는지 → 첫 안전한 액션까지', {}, async () => ({
4
+ messages: [{
5
+ role: 'user',
6
+ content: {
7
+ type: 'text',
8
+ text: [
9
+ '나는 mimi-seed 를 처음 써봐. 온보딩을 도와줘.',
10
+ '',
11
+ '진행 순서:',
12
+ '1. mimi_seed_status 호출 — 연결 상태 스캔 (Claude Code 라면 먼저 ToolSearch(query="select:mimi_seed_status") 로 schema 로드)',
13
+ '2. 리소스 mimi-seed://tools/catalog 를 읽고 뭘 할 수 있는지 도메인별로 간단히 요약 (150+ 도구)',
14
+ '3. 내 목표를 물어봐: ① 스토어 출시/운영 ② Firebase/AdMob 설정 ③ 분석(GA4/Search Console/Ads/BigQuery) ④ 소셜 포스팅 ⑤ CI/Jenkins',
15
+ '4. 목표에 필요한 자격증명이 ❌ 면: 터미널에서 `npx mimi-seed setup` 실행을 안내 (대화형이므로 네가 대신 실행하지 말 것)',
16
+ '5. 자격증명이 준비되면 목표에 맞는 첫 읽기 전용 액션을 실행해서 보여줘 (예: playstore_list_tracks · appstore_list_apps · firebase_list_projects · admob_list_accounts)',
17
+ '6. 다음 단계 제안: /mimi-seed:deploy · /mimi-seed:health · /mimi-seed:review-inbox, 심화 규약은 mimi-seed://agent/guide',
18
+ ].join('\n'),
19
+ },
20
+ }],
21
+ }));
3
22
  server.prompt('deploy', '앱 출시 전 체크 → 릴리즈 노트 생성 → 스토어 적용까지 한 번에 진행', {
4
23
  packageName: z.string().optional().describe('Android 패키지명 (Play Store 출시 시)'),
5
24
  appId: z.string().optional().describe('App Store 앱 ID (iOS 출시 시)'),
@@ -34,7 +53,7 @@ export function registerPrompts(server) {
34
53
  '현재 Mimi Seed 연결 상태와 앱 출시 준비도를 요약해줘.',
35
54
  '',
36
55
  '확인 순서:',
37
- '1. mimi_seed_status 호출 — 9개 서비스 전체 연결 상태 스캔',
56
+ '1. mimi_seed_status 호출 — 전체 서비스 연결 상태 스캔',
38
57
  '2. ❌ 필수 항목(Google OAuth / Play SA / App Store)이 있으면 먼저 설정 안내',
39
58
  '3. firebase_list_projects 로 연결된 Firebase 프로젝트 확인 (OAuth 연결 시)',
40
59
  '4. playstore_check_submission_risks / appstore_check_submission_risks 로 블로커 점검',
@@ -111,7 +111,7 @@ export function registerAuthTools(server) {
111
111
  // ── 전체 연결 상태 진단 ────────────────────────────────────────────────────
112
112
  server.tool('mimi_seed_status', [
113
113
  '⭐ 새 세션을 시작하거나 "뭐가 연결됐지?" 라는 질문엔 이 도구를 먼저 호출하세요.',
114
- '10개 서비스(Google OAuth / Play SA / App Store / Jenkins / CI / Google Ads / Facebook / Instagram / Threads / BigQuery)',
114
+ '전체 서비스(Google OAuth / Play SA / App Store / Jenkins / CI / Google Ads / Facebook / Instagram / Threads / BigQuery)',
115
115
  '설정 상태를 한 번에 스캔해 ✅ / ❌ 트래픽 라이트 리포트와 번호 매긴 다음 단계를 반환합니다.',
116
116
  '미설정 서비스마다 어떤 도구를 호출하면 되는지 구체적으로 알려줍니다.',
117
117
  ].join(' '), {}, async () => {
@@ -1,2 +1,7 @@
1
1
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ /** tool-manifest.json 의 형태. 테스트들도 이 타입을 import 해 캐스트 드리프트를 막는다. */
3
+ export type ToolManifest = {
4
+ total: number;
5
+ domains: Record<string, string[]>;
6
+ };
2
7
  export declare function registerResources(server: McpServer): void;
package/dist/resources.js CHANGED
@@ -1,4 +1,121 @@
1
+ import { readFileSync } from 'node:fs';
1
2
  import { ensureFreshAccessToken } from './auth/google-auth.js';
3
+ // assets/agent-guide.md = docs/agent-guide.md 의 배포용 사본 (npm 배포본에는 docs/ 가 없다).
4
+ // 갱신은 `npm run plugin:sync`, 드리프트는 prompts-resources.test.ts 가 잡는다.
5
+ // 읽기 실패는 정상 설치에서 불가능하다(files 화이트리스트에 포함) — 그래서 폴백은 가이드
6
+ // 요약본이 아니라 "깨진 설치" 신호 + 원본 포인터만 담는다. 요약본을 하나 더 관리하지 않는다.
7
+ const AGENT_GUIDE_FALLBACK = [
8
+ '# Mimi Seed agent guide — 자산 누락 (degraded)',
9
+ '',
10
+ '⚠️ 이 설치본에서 assets/agent-guide.md 를 읽지 못했습니다 — 패키지가 손상됐습니다.',
11
+ '`npx -y @yoonion/mimi-seed-mcp` 재설치(필요 시 npx 캐시 정리) 후 새 세션을 여세요.',
12
+ '',
13
+ '가이드 전문: https://github.com/jeonghwanko/mimi-seed-sdk/blob/main/docs/agent-guide.md',
14
+ '최소 안전수칙: 스토어 제출·승격·삭제·공개 게시는 사용자 명시 동의 없이 실행하지 않는다.',
15
+ ].join('\n');
16
+ function readPackageAsset(relativePath) {
17
+ try {
18
+ // src/ 와 dist/ 모두 패키지 루트 바로 아래라 ../ 가 같은 곳을 가리킨다 (index.ts 의 package.json 읽기와 동일 패턴).
19
+ return readFileSync(new URL(relativePath, import.meta.url), 'utf8');
20
+ }
21
+ catch {
22
+ return null;
23
+ }
24
+ }
25
+ /** 도메인 id → 라벨·필요 자격증명·한줄 요약. 키 집합은 tool-manifest.json 의 domains 와
26
+ * 일치해야 한다 (prompts-resources.test.ts 가 강제) — 도메인을 추가하면 여기도 추가할 것. */
27
+ const DOMAIN_SUMMARY = {
28
+ playstore: {
29
+ label: 'Google Play',
30
+ credential: 'Google OAuth (CI/헤드리스는 Play 서비스 계정)',
31
+ summary: '리스팅·트랙 릴리스·이미지·리뷰 답변·통계·서비스 계정 등록',
32
+ },
33
+ appstore: {
34
+ label: 'App Store Connect',
35
+ credential: 'ASC API 키 (mimi-seed auth appstore)',
36
+ summary: '버전·빌드 attach·What\'s New·스크린샷·IAP 심사 메타데이터·심사 제출',
37
+ },
38
+ firebase: {
39
+ label: 'Firebase',
40
+ credential: 'Google OAuth',
41
+ summary: '프로젝트/앱 생성·설정 파일 다운로드·서비스 활성화',
42
+ },
43
+ admob: {
44
+ label: 'AdMob',
45
+ credential: 'Google OAuth',
46
+ summary: '앱·광고 단위 생성, 오늘 수익·기간 리포트',
47
+ },
48
+ iam: {
49
+ label: 'Google Cloud IAM',
50
+ credential: 'Google OAuth',
51
+ summary: '서비스 계정 생성·키 발급·IAM 정책 바인딩',
52
+ },
53
+ bigquery: {
54
+ label: 'BigQuery',
55
+ credential: 'Google OAuth (또는 BigQuery 서비스 계정)',
56
+ summary: '쿼리 실행·데이터셋/테이블/스키마 조회',
57
+ },
58
+ ga4: {
59
+ label: 'Google Analytics 4',
60
+ credential: 'Google OAuth',
61
+ summary: '계정/속성·데이터 스트림 관리, 리포트 실행',
62
+ },
63
+ gsc: {
64
+ label: 'Search Console',
65
+ credential: 'Google OAuth',
66
+ summary: 'URL 검사·검색 성과 분석·사이트맵 제출',
67
+ },
68
+ googleads: {
69
+ label: 'Google Ads',
70
+ credential: 'Google Ads 설정 (mimi-seed auth googleads, adwords 스코프)',
71
+ summary: '캠페인 목록·캠페인/UAC 리포트',
72
+ },
73
+ ci: {
74
+ label: 'CI (GitHub Actions / GitLab)',
75
+ credential: 'GitHub/GitLab 토큰 (mimi-seed auth ci)',
76
+ summary: '워크플로 조회·빌드 트리거/상태/취소 — Jenkins 빌드는 대상 아님',
77
+ },
78
+ jenkins: {
79
+ label: 'Jenkins',
80
+ credential: 'Jenkins URL + API 토큰 (mimi-seed auth jenkins)',
81
+ summary: '크리덴셜·keystore 업로드·잡 생성/수정 — 빌드 트리거 도구는 없음',
82
+ },
83
+ android: {
84
+ label: 'Android 서명',
85
+ credential: '없음 (로컬 파일 작업)',
86
+ summary: 'keystore 생성·서명 설정·Jenkins 로 Play SA 업로드',
87
+ },
88
+ facebook: {
89
+ label: 'Facebook',
90
+ credential: 'Facebook 페이지 토큰 (mimi-seed auth facebook)',
91
+ summary: '페이지 텍스트/사진/링크 포스팅',
92
+ },
93
+ instagram: {
94
+ label: 'Instagram',
95
+ credential: 'Instagram 토큰 (mimi-seed auth instagram)',
96
+ summary: '사진·캐러셀·릴스 포스팅',
97
+ },
98
+ threads: {
99
+ label: 'Threads',
100
+ credential: 'Threads 토큰 (mimi-seed auth threads)',
101
+ summary: '텍스트/이미지 포스팅·토큰 갱신',
102
+ },
103
+ checks: {
104
+ label: '출시 점검',
105
+ credential: '점검 대상 스토어의 자격증명',
106
+ summary: '제출 전 위험 점검·스크린샷 규격 검증·릴리스 상태',
107
+ },
108
+ ai: {
109
+ label: 'AI 생성',
110
+ credential: 'ANTHROPIC_API_KEY 환경변수',
111
+ summary: '커밋 기반 릴리스 노트·리뷰 답변 초안 생성',
112
+ },
113
+ auth: {
114
+ label: '연결/진단',
115
+ credential: '없음 (이것이 셋업 도구)',
116
+ summary: '전체 연결 상태 스캔(mimi_seed_status)·OAuth 시작·원격 크리덴셜 동기화',
117
+ },
118
+ };
2
119
  export function registerResources(server) {
3
120
  server.resource('auth-status', 'mimi-seed://auth/status', { description: 'Google OAuth 인증 상태 — fresh / refreshed / expired / unauthenticated', mimeType: 'application/json' }, async () => {
4
121
  const r = await ensureFreshAccessToken();
@@ -17,35 +134,56 @@ export function registerResources(server) {
17
134
  }],
18
135
  };
19
136
  });
20
- server.resource('agent-guide', 'mimi-seed://agent/guide', { description: 'Mimi Seed 에이전트 역할 정의 — 출시 워크플로우 · 주의사항 · 슬래시 커맨드', mimeType: 'text/markdown' }, async () => ({
137
+ server.resource('agent-guide', 'mimi-seed://agent/guide', {
138
+ description: 'Mimi Seed 에이전트 운영 규약 전문 (docs/agent-guide.md) — deferred 도구 로딩·ToolSearch select: 배치·호출 순서·비가역 액션 안전수칙',
139
+ mimeType: 'text/markdown',
140
+ }, async () => ({
21
141
  contents: [{
22
142
  uri: 'mimi-seed://agent/guide',
23
143
  mimeType: 'text/markdown',
24
- text: [
25
- '# Mimi Seed — 앱 출시·운영 Agent',
26
- '',
27
- '당신은 Mimi Seed MCP를 통해 인디 개발자의 앱 출시와 운영을 돕는 에이전트입니다.',
28
- 'Google Play · App Store · Firebase · AdMob · CI/CD · BigQuery를 직접 제어하는 150+ 도구를 사용할 수 있습니다.',
29
- '',
30
- '## 출시 요청 처리 순서',
31
- '',
32
- '1. **항상** `playstore_check_submission_risks` / `appstore_check_submission_risks` 로 블로커 먼저 확인',
33
- '2. 릴리즈 노트: `generate_release_notes_from_commits` → 검토 → 적용',
34
- '3. **쓰기 작업**(submit, apply, reply 등)은 반드시 사용자 명시 동의 후 실행',
35
- '4. 완료 후 결과 요약 제공',
36
- '',
37
- '## 슬래시 커맨드',
38
- '',
39
- '- `/mimi-seed:deploy` — 전체 출시 파이프라인',
40
- '- `/mimi-seed:health` — 연결·인증 상태 빠른 확인',
41
- '- `/mimi-seed:review-inbox` — 미답변 리뷰 조회 + 답변 생성',
42
- '',
43
- '## 주의사항',
44
- '',
45
- '- `playstore_submit_release(status=completed)` — 비가역, 반드시 명시 동의 필요',
46
- '- `appstore_submit_for_review` — 비가역, 반드시 명시 동의 필요',
47
- '- `playstore_reply_review` — 공개 게시, 반드시 검토 후 동의 필요',
48
- ].join('\n'),
144
+ text: readPackageAsset('../assets/agent-guide.md') ?? AGENT_GUIDE_FALLBACK,
49
145
  }],
50
146
  }));
147
+ server.resource('tools-catalog', 'mimi-seed://tools/catalog', {
148
+ description: '150+ 도구 전체 카탈로그 — 도메인별 도구 목록·필요 자격증명·한줄 요약. "mimi-seed 로 뭘 할 수 있어?" 에는 이 리소스를 읽고 답하세요.',
149
+ mimeType: 'application/json',
150
+ }, async () => {
151
+ // LLM 이 읽는 페이로드라 compact 로 직렬화한다 (pretty 들여쓰기는 ~40% 바이트 낭비).
152
+ let payload;
153
+ try {
154
+ const raw = readFileSync(new URL('../tool-manifest.json', import.meta.url), 'utf8');
155
+ const manifest = JSON.parse(raw);
156
+ if (typeof manifest?.total !== 'number' || typeof manifest?.domains !== 'object' || manifest.domains === null) {
157
+ throw new Error('tool-manifest.json 의 형태가 예상과 다릅니다');
158
+ }
159
+ payload = JSON.stringify({
160
+ total: manifest.total,
161
+ deferredHint: 'Claude Code 에서는 도구 schema 가 lazy 로드됩니다 — 호출 전 ToolSearch(query="select:<tool,...>") 로 선로드하세요. 상세: mimi-seed://agent/guide',
162
+ domains: Object.entries(manifest.domains).map(([id, tools]) => ({
163
+ id,
164
+ label: DOMAIN_SUMMARY[id]?.label ?? id,
165
+ credential: DOMAIN_SUMMARY[id]?.credential ?? '알 수 없음',
166
+ summary: DOMAIN_SUMMARY[id]?.summary ?? '',
167
+ toolCount: tools.length,
168
+ tools,
169
+ })),
170
+ });
171
+ }
172
+ catch (e) {
173
+ // 가짜 성공(빈 카탈로그)을 서빙하지 않는다 — 깨진 설치임을 명시적으로 알린다.
174
+ payload = JSON.stringify({
175
+ error: 'tool-manifest.json 을 읽지 못했습니다 — 패키지가 손상됐습니다. `npx -y @yoonion/mimi-seed-mcp` 재설치 후 새 세션을 여세요.',
176
+ detail: e instanceof Error ? e.message : String(e),
177
+ total: null,
178
+ domains: [],
179
+ });
180
+ }
181
+ return {
182
+ contents: [{
183
+ uri: 'mimi-seed://tools/catalog',
184
+ mimeType: 'application/json',
185
+ text: payload,
186
+ }],
187
+ };
188
+ });
51
189
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yoonion/mimi-seed-mcp",
3
- "version": "0.10.2",
3
+ "version": "0.11.0",
4
4
  "description": "Mimi Seed MCP server — Firebase + AdMob + Google Play + App Store management for Claude Code / Codex / Cursor / any MCP client.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -18,6 +18,8 @@
18
18
  },
19
19
  "files": [
20
20
  "dist",
21
+ "assets",
22
+ "tool-manifest.json",
21
23
  "LICENSE"
22
24
  ],
23
25
  "scripts": {
@@ -26,7 +28,7 @@
26
28
  "auth": "tsx src/auth/cli.ts",
27
29
  "test": "vitest run",
28
30
  "test:watch": "vitest",
29
- "prepublishOnly": "tsc"
31
+ "prepublishOnly": "node ../../scripts/sync-agent-guide.mjs --check && tsc"
30
32
  },
31
33
  "keywords": [
32
34
  "mcp",
@@ -0,0 +1,205 @@
1
+ {
2
+ "$comment": "등록된 MCP 도구의 SSOT. src/__tests__/tool-manifest.test.ts 가 실제 서버 등록 목록과 diff 하여 강제한다. 도구 추가/삭제/개명 시 이 파일을 함께 갱신할 것 — 산문 문서에는 정확한 개수를 쓰지 말고 이 파일을 가리킬 것.",
3
+ "total": 163,
4
+ "domains": {
5
+ "admob": [
6
+ "admob_list_accounts",
7
+ "admob_list_apps",
8
+ "admob_list_ad_units",
9
+ "admob_get_today_earnings",
10
+ "admob_get_report",
11
+ "admob_create_app",
12
+ "admob_create_ad_unit"
13
+ ],
14
+ "ai": [
15
+ "generate_release_notes_from_commits",
16
+ "generate_review_reply"
17
+ ],
18
+ "android": [
19
+ "android_signing_setup",
20
+ "android_generate_keystore",
21
+ "jenkins_upload_playstore_sa"
22
+ ],
23
+ "appstore": [
24
+ "appstore_list_apps",
25
+ "appstore_verify_credentials",
26
+ "appstore_get_app",
27
+ "appstore_list_versions",
28
+ "appstore_create_version",
29
+ "appstore_attach_build",
30
+ "appstore_attach_latest_build",
31
+ "appstore_get_metadata",
32
+ "appstore_update_localization",
33
+ "appstore_list_screenshots",
34
+ "appstore_upload_screenshot",
35
+ "appstore_delete_screenshot",
36
+ "appstore_delete_screenshot_set",
37
+ "appstore_update_whats_new",
38
+ "appstore_update_review_notes",
39
+ "appstore_get_review_notes",
40
+ "appstore_list_builds",
41
+ "appstore_list_beta_groups",
42
+ "appstore_get_app_info",
43
+ "appstore_list_app_info_localizations",
44
+ "appstore_update_app_info_localization",
45
+ "appstore_create_app_info_localization",
46
+ "appstore_list_reviews",
47
+ "appstore_reply_review",
48
+ "appstore_create_inapp_purchase",
49
+ "appstore_create_subscription",
50
+ "appstore_list_products",
51
+ "appstore_update_product_review_note",
52
+ "appstore_upload_product_review_screenshot",
53
+ "appstore_update_product",
54
+ "appstore_delete_product",
55
+ "appstore_plan_release",
56
+ "appstore_submit_for_review",
57
+ "appstore_cancel_review"
58
+ ],
59
+ "auth": [
60
+ "mimi_seed_status",
61
+ "mimi_seed_auth_start",
62
+ "mimi_seed_auth_status",
63
+ "mimi_seed_remote_sync_credentials"
64
+ ],
65
+ "bigquery": [
66
+ "bigquery_run_query",
67
+ "bigquery_list_datasets",
68
+ "bigquery_list_tables",
69
+ "bigquery_get_table_schema",
70
+ "bigquery_auth_status"
71
+ ],
72
+ "checks": [
73
+ "playstore_check_submission_risks",
74
+ "appstore_check_submission_risks",
75
+ "screenshot_validate",
76
+ "release_status"
77
+ ],
78
+ "ci": [
79
+ "ci_save_config",
80
+ "ci_list_workflows",
81
+ "ci_trigger_build",
82
+ "ci_get_build_status",
83
+ "ci_list_recent_builds",
84
+ "ci_cancel_build"
85
+ ],
86
+ "facebook": [
87
+ "facebook_save_config",
88
+ "facebook_list_pages",
89
+ "facebook_get_page",
90
+ "facebook_post_photo",
91
+ "facebook_post_multi_photo",
92
+ "facebook_current_config"
93
+ ],
94
+ "firebase": [
95
+ "firebase_list_projects",
96
+ "firebase_get_project",
97
+ "firebase_create_project",
98
+ "firebase_list_android_apps",
99
+ "firebase_create_android_app",
100
+ "firebase_get_android_config",
101
+ "firebase_delete_android_app",
102
+ "firebase_list_ios_apps",
103
+ "firebase_create_ios_app",
104
+ "firebase_get_ios_config",
105
+ "firebase_delete_ios_app",
106
+ "firebase_list_web_apps",
107
+ "firebase_create_web_app",
108
+ "firebase_get_web_config",
109
+ "firebase_delete_web_app",
110
+ "firebase_enable_service",
111
+ "firebase_enable_common_services",
112
+ "firebase_list_enabled_services",
113
+ "firebase_link_analytics",
114
+ "firebase_get_analytics_details"
115
+ ],
116
+ "ga4": [
117
+ "ga4_list_account_summaries",
118
+ "ga4_list_properties",
119
+ "ga4_create_property",
120
+ "ga4_create_data_stream",
121
+ "ga4_list_data_streams",
122
+ "ga4_run_report"
123
+ ],
124
+ "googleads": [
125
+ "googleads_save_config",
126
+ "googleads_list_campaigns",
127
+ "googleads_get_campaign_report",
128
+ "googleads_get_uac_report",
129
+ "googleads_list_accessible_customers",
130
+ "googleads_config_status"
131
+ ],
132
+ "gsc": [
133
+ "gsc_list_sites",
134
+ "gsc_list_sitemaps",
135
+ "gsc_get_sitemap",
136
+ "gsc_submit_sitemap",
137
+ "gsc_inspect_url",
138
+ "gsc_search_analytics"
139
+ ],
140
+ "iam": [
141
+ "iam_list_service_accounts",
142
+ "iam_create_service_account",
143
+ "iam_list_keys",
144
+ "iam_create_key",
145
+ "iam_add_iam_policy_binding"
146
+ ],
147
+ "instagram": [
148
+ "instagram_save_config",
149
+ "instagram_get_account",
150
+ "instagram_post_image",
151
+ "instagram_post_carousel"
152
+ ],
153
+ "jenkins": [
154
+ "jenkins_status",
155
+ "jenkins_save_config",
156
+ "jenkins_list_credentials",
157
+ "jenkins_create_credential",
158
+ "jenkins_upload_keystore",
159
+ "jenkins_delete_credential",
160
+ "jenkins_list_jobs",
161
+ "jenkins_get_job_config",
162
+ "jenkins_create_job",
163
+ "jenkins_update_job"
164
+ ],
165
+ "playstore": [
166
+ "playstore_get_app",
167
+ "playstore_update_details",
168
+ "playstore_get_listing",
169
+ "playstore_update_listing",
170
+ "playstore_list_tracks",
171
+ "playstore_get_statistics",
172
+ "playstore_list_images",
173
+ "playstore_upload_image",
174
+ "playstore_delete_all_images",
175
+ "playstore_replace_images",
176
+ "playstore_update_release_notes",
177
+ "playstore_update_latest_release_notes",
178
+ "playstore_list_reviews",
179
+ "playstore_reply_review",
180
+ "playstore_list_inapp_products",
181
+ "playstore_list_subscriptions",
182
+ "playstore_create_onetime_product",
183
+ "playstore_create_subscription",
184
+ "playstore_verify_service_account",
185
+ "playstore_register_service_account",
186
+ "playstore_list_service_accounts",
187
+ "playstore_delete_service_account",
188
+ "playstore_plan_release",
189
+ "playstore_submit_release",
190
+ "playstore_promote_release",
191
+ "playstore_list_products",
192
+ "playstore_update_product",
193
+ "playstore_delete_product",
194
+ "setup_playstore_connection"
195
+ ],
196
+ "threads": [
197
+ "threads_save_config",
198
+ "threads_refresh_token",
199
+ "threads_get_account",
200
+ "threads_post",
201
+ "threads_post_carousel",
202
+ "threads_current_config"
203
+ ]
204
+ }
205
+ }