@yoonion/mimi-seed-mcp 0.4.0 → 0.5.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/LICENSE +75 -75
- package/README.md +241 -235
- package/dist/admob/cli.js +20 -20
- package/dist/auth/google-auth.js +7 -7
- package/dist/firebase/cli.js +27 -27
- package/dist/ga4/cli.js +27 -27
- package/dist/googleads/tools.js +54 -54
- package/dist/lib/project-manifest.d.ts +36 -0
- package/dist/lib/project-manifest.js +52 -0
- package/dist/registers/auth.js +88 -5
- package/package.json +4 -1
package/LICENSE
CHANGED
|
@@ -1,75 +1,75 @@
|
|
|
1
|
-
# PolyForm Noncommercial License 1.0.0
|
|
2
|
-
|
|
3
|
-
<https://polyformproject.org/licenses/noncommercial/1.0.0>
|
|
4
|
-
|
|
5
|
-
Required Notice: Copyright 2026 Pryzm GG (https://mimi-seed.pryzm.gg)
|
|
6
|
-
|
|
7
|
-
## Acceptance
|
|
8
|
-
|
|
9
|
-
In order to get any license under these terms, you must agree to them as both strict obligations and conditions to all your licenses.
|
|
10
|
-
|
|
11
|
-
## Copyright License
|
|
12
|
-
|
|
13
|
-
The licensor grants you a copyright license for the software to do everything you might do with the software that would otherwise infringe the licensor's copyright in it for any permitted purpose. However, you may only distribute the software according to [Distribution License](#distribution-license) and make changes or new works based on the software according to [Changes and New Works License](#changes-and-new-works-license).
|
|
14
|
-
|
|
15
|
-
## Distribution License
|
|
16
|
-
|
|
17
|
-
The licensor grants you an additional copyright license to distribute copies of the software. Your license to distribute covers distributing the software with changes and new works permitted by [Changes and New Works License](#changes-and-new-works-license).
|
|
18
|
-
|
|
19
|
-
## Notices
|
|
20
|
-
|
|
21
|
-
You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms or the URL for them above, as well as copies of any plain-text lines beginning with `Required Notice:` that the licensor provided with the software. For example:
|
|
22
|
-
|
|
23
|
-
> Required Notice: Copyright Yoyodyne, Inc. (http://example.com)
|
|
24
|
-
|
|
25
|
-
## Changes and New Works License
|
|
26
|
-
|
|
27
|
-
The licensor grants you an additional copyright license to make changes and new works based on the software for any permitted purpose.
|
|
28
|
-
|
|
29
|
-
## Patent License
|
|
30
|
-
|
|
31
|
-
The licensor grants you a patent license for the software that covers patent claims the licensor can license, or becomes able to license, that you would infringe by using the software.
|
|
32
|
-
|
|
33
|
-
## Noncommercial Purposes
|
|
34
|
-
|
|
35
|
-
Any noncommercial purpose is a permitted purpose.
|
|
36
|
-
|
|
37
|
-
## Personal Uses
|
|
38
|
-
|
|
39
|
-
Personal use for research, experiment, and testing for the benefit of public knowledge, personal study, private entertainment, hobby projects, amateur pursuits, or religious observance, without any anticipated commercial application, is use for a permitted purpose.
|
|
40
|
-
|
|
41
|
-
## Noncommercial Organizations
|
|
42
|
-
|
|
43
|
-
Use by any charitable organization, educational institution, public research organization, public safety or health organization, environmental protection organization, or government institution is use for a permitted purpose regardless of the source of funding or obligations resulting from the funding.
|
|
44
|
-
|
|
45
|
-
## Fair Use
|
|
46
|
-
|
|
47
|
-
You may have "fair use" rights for the software under the law. These terms do not limit them.
|
|
48
|
-
|
|
49
|
-
## No Other Rights
|
|
50
|
-
|
|
51
|
-
These terms do not allow you to sublicense or transfer any of your licenses to anyone else, or prevent the licensor from granting licenses to anyone else. These terms do not imply any other licenses.
|
|
52
|
-
|
|
53
|
-
## Patent Defense
|
|
54
|
-
|
|
55
|
-
If you make any written claim that the software infringes or contributes to infringement of any patent, your patent license for the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company.
|
|
56
|
-
|
|
57
|
-
## Violations
|
|
58
|
-
|
|
59
|
-
The first time you are notified in writing that you have violated any of these terms, or done anything with the software not covered by your licenses, your licenses can nonetheless continue if you come into full compliance with these terms, and take practical steps to correct past violations, within 32 days of receiving notice. Otherwise, all your licenses end immediately.
|
|
60
|
-
|
|
61
|
-
## No Liability
|
|
62
|
-
|
|
63
|
-
***As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim.***
|
|
64
|
-
|
|
65
|
-
## Definitions
|
|
66
|
-
|
|
67
|
-
The **licensor** is the individual or entity offering these terms, and the **software** is the software the licensor makes available under these terms.
|
|
68
|
-
|
|
69
|
-
**You** refers to the individual or entity agreeing to these terms.
|
|
70
|
-
|
|
71
|
-
**Your company** is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization. **Control** means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect.
|
|
72
|
-
|
|
73
|
-
**Your licenses** are all the licenses granted to you for the software under these terms.
|
|
74
|
-
|
|
75
|
-
**Use** means anything you do with the software requiring one of your licenses.
|
|
1
|
+
# PolyForm Noncommercial License 1.0.0
|
|
2
|
+
|
|
3
|
+
<https://polyformproject.org/licenses/noncommercial/1.0.0>
|
|
4
|
+
|
|
5
|
+
Required Notice: Copyright 2026 Pryzm GG (https://mimi-seed.pryzm.gg)
|
|
6
|
+
|
|
7
|
+
## Acceptance
|
|
8
|
+
|
|
9
|
+
In order to get any license under these terms, you must agree to them as both strict obligations and conditions to all your licenses.
|
|
10
|
+
|
|
11
|
+
## Copyright License
|
|
12
|
+
|
|
13
|
+
The licensor grants you a copyright license for the software to do everything you might do with the software that would otherwise infringe the licensor's copyright in it for any permitted purpose. However, you may only distribute the software according to [Distribution License](#distribution-license) and make changes or new works based on the software according to [Changes and New Works License](#changes-and-new-works-license).
|
|
14
|
+
|
|
15
|
+
## Distribution License
|
|
16
|
+
|
|
17
|
+
The licensor grants you an additional copyright license to distribute copies of the software. Your license to distribute covers distributing the software with changes and new works permitted by [Changes and New Works License](#changes-and-new-works-license).
|
|
18
|
+
|
|
19
|
+
## Notices
|
|
20
|
+
|
|
21
|
+
You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms or the URL for them above, as well as copies of any plain-text lines beginning with `Required Notice:` that the licensor provided with the software. For example:
|
|
22
|
+
|
|
23
|
+
> Required Notice: Copyright Yoyodyne, Inc. (http://example.com)
|
|
24
|
+
|
|
25
|
+
## Changes and New Works License
|
|
26
|
+
|
|
27
|
+
The licensor grants you an additional copyright license to make changes and new works based on the software for any permitted purpose.
|
|
28
|
+
|
|
29
|
+
## Patent License
|
|
30
|
+
|
|
31
|
+
The licensor grants you a patent license for the software that covers patent claims the licensor can license, or becomes able to license, that you would infringe by using the software.
|
|
32
|
+
|
|
33
|
+
## Noncommercial Purposes
|
|
34
|
+
|
|
35
|
+
Any noncommercial purpose is a permitted purpose.
|
|
36
|
+
|
|
37
|
+
## Personal Uses
|
|
38
|
+
|
|
39
|
+
Personal use for research, experiment, and testing for the benefit of public knowledge, personal study, private entertainment, hobby projects, amateur pursuits, or religious observance, without any anticipated commercial application, is use for a permitted purpose.
|
|
40
|
+
|
|
41
|
+
## Noncommercial Organizations
|
|
42
|
+
|
|
43
|
+
Use by any charitable organization, educational institution, public research organization, public safety or health organization, environmental protection organization, or government institution is use for a permitted purpose regardless of the source of funding or obligations resulting from the funding.
|
|
44
|
+
|
|
45
|
+
## Fair Use
|
|
46
|
+
|
|
47
|
+
You may have "fair use" rights for the software under the law. These terms do not limit them.
|
|
48
|
+
|
|
49
|
+
## No Other Rights
|
|
50
|
+
|
|
51
|
+
These terms do not allow you to sublicense or transfer any of your licenses to anyone else, or prevent the licensor from granting licenses to anyone else. These terms do not imply any other licenses.
|
|
52
|
+
|
|
53
|
+
## Patent Defense
|
|
54
|
+
|
|
55
|
+
If you make any written claim that the software infringes or contributes to infringement of any patent, your patent license for the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company.
|
|
56
|
+
|
|
57
|
+
## Violations
|
|
58
|
+
|
|
59
|
+
The first time you are notified in writing that you have violated any of these terms, or done anything with the software not covered by your licenses, your licenses can nonetheless continue if you come into full compliance with these terms, and take practical steps to correct past violations, within 32 days of receiving notice. Otherwise, all your licenses end immediately.
|
|
60
|
+
|
|
61
|
+
## No Liability
|
|
62
|
+
|
|
63
|
+
***As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim.***
|
|
64
|
+
|
|
65
|
+
## Definitions
|
|
66
|
+
|
|
67
|
+
The **licensor** is the individual or entity offering these terms, and the **software** is the software the licensor makes available under these terms.
|
|
68
|
+
|
|
69
|
+
**You** refers to the individual or entity agreeing to these terms.
|
|
70
|
+
|
|
71
|
+
**Your company** is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization. **Control** means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect.
|
|
72
|
+
|
|
73
|
+
**Your licenses** are all the licenses granted to you for the software under these terms.
|
|
74
|
+
|
|
75
|
+
**Use** means anything you do with the software requiring one of your licenses.
|
package/README.md
CHANGED
|
@@ -1,235 +1,241 @@
|
|
|
1
|
-
# @yoonion/mimi-seed-mcp
|
|
2
|
-
|
|
3
|
-
**Mimi Seed** — Firebase · AdMob · Google Play · App Store Connect를 AI 콘솔에서 관리. Claude Code / Codex / Cursor / 기타 MCP 클라이언트에서 한 줄 등록으로 사용.
|
|
4
|
-
|
|
5
|
-
> 이 패키지는 Mimi Seed의 **로컬 MCP 서버**만 포함합니다. 웹 콘솔(Next.js 앱)은 <https://mimi-seed.pryzm.gg/tool>.
|
|
6
|
-
|
|
7
|
-
## 설치
|
|
8
|
-
|
|
9
|
-
Claude Code:
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
claude mcp add mimi-seed -- npx -y @yoonion/mimi-seed-mcp
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
Codex (`~/.codex/config.toml`):
|
|
16
|
-
|
|
17
|
-
```toml
|
|
18
|
-
[mcp_servers.mimi-seed]
|
|
19
|
-
command = "npx"
|
|
20
|
-
args = ["-y", "@yoonion/mimi-seed-mcp"]
|
|
21
|
-
enabled = true
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
Claude Desktop (`claude_desktop_config.json`):
|
|
25
|
-
|
|
26
|
-
```json
|
|
27
|
-
{
|
|
28
|
-
"mcpServers": {
|
|
29
|
-
"mimi-seed": {
|
|
30
|
-
"command": "npx",
|
|
31
|
-
"args": ["-y", "@yoonion/mimi-seed-mcp"]
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
## 첫 사용 전 인증
|
|
38
|
-
|
|
39
|
-
```bash
|
|
40
|
-
npx -y @yoonion/mimi-seed-mcp mimi-seed-auth
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
브라우저가 열리면 Google 계정으로 로그인. 토큰은 `~/.mimi-seed/tokens.json`에 저장되고 자동 갱신됨.
|
|
44
|
-
|
|
45
|
-
플랫폼별 추가 인증 (필요한 것만):
|
|
46
|
-
|
|
47
|
-
```bash
|
|
48
|
-
npx -y @yoonion/mimi-seed-mcp mimi-seed-appstore-auth # App Store Connect (API Key)
|
|
49
|
-
npx -y @yoonion/mimi-seed-mcp mimi-seed-playstore-auth # Google Play 서비스 계정 JSON
|
|
50
|
-
npx -y @yoonion/mimi-seed-mcp mimi-seed-bigquery-auth # BigQuery (Crashlytics export 등)
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
- **App Store Connect**: Users and Access → Keys에서 API Key 생성 후 Issuer ID / Key ID / .p8 경로 입력 → `~/.mimi-seed/appstore.json`
|
|
54
|
-
- **Google Play**: Play Console 서비스 계정 JSON 경로 입력 (패키지별 등록)
|
|
55
|
-
- **BigQuery**: Google OAuth 또는 서비스 계정으로 데이터셋 조회 권한 부여
|
|
56
|
-
|
|
57
|
-
AI 기능(릴리즈 노트 생성, 리뷰 답변)을 쓰려면:
|
|
58
|
-
|
|
59
|
-
```bash
|
|
60
|
-
export ANTHROPIC_API_KEY=sk-ant-...
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
---
|
|
64
|
-
|
|
65
|
-
## 제공 도구 (
|
|
66
|
-
|
|
67
|
-
| 영역 | 도구 수 | 주요 도구 |
|
|
68
|
-
|------|---------|-----------|
|
|
69
|
-
| App Store Connect |
|
|
70
|
-
| Google Play |
|
|
71
|
-
| Firebase |
|
|
72
|
-
| AdMob | 7 | `admob_list_apps` / `admob_create_ad_unit` / `admob_get_today_earnings` / `admob_get_report` |
|
|
73
|
-
| CI/CD (GitHub Actions · GitLab) | 6 | `ci_trigger_build` / `ci_get_build_status` / `ci_list_workflows` / `ci_cancel_build` |
|
|
74
|
-
|
|
|
75
|
-
|
|
|
76
|
-
|
|
|
77
|
-
|
|
|
78
|
-
|
|
|
79
|
-
|
|
|
80
|
-
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
|
99
|
-
|
|
100
|
-
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
-
|
|
193
|
-
-
|
|
194
|
-
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
1
|
+
# @yoonion/mimi-seed-mcp
|
|
2
|
+
|
|
3
|
+
**Mimi Seed** — Firebase · AdMob · Google Play · App Store Connect를 AI 콘솔에서 관리. Claude Code / Codex / Cursor / 기타 MCP 클라이언트에서 한 줄 등록으로 사용.
|
|
4
|
+
|
|
5
|
+
> 이 패키지는 Mimi Seed의 **로컬 MCP 서버**만 포함합니다. 웹 콘솔(Next.js 앱)은 <https://mimi-seed.pryzm.gg/tool>.
|
|
6
|
+
|
|
7
|
+
## 설치
|
|
8
|
+
|
|
9
|
+
Claude Code:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
claude mcp add mimi-seed -- npx -y @yoonion/mimi-seed-mcp
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Codex (`~/.codex/config.toml`):
|
|
16
|
+
|
|
17
|
+
```toml
|
|
18
|
+
[mcp_servers.mimi-seed]
|
|
19
|
+
command = "npx"
|
|
20
|
+
args = ["-y", "@yoonion/mimi-seed-mcp"]
|
|
21
|
+
enabled = true
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Claude Desktop (`claude_desktop_config.json`):
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"mcpServers": {
|
|
29
|
+
"mimi-seed": {
|
|
30
|
+
"command": "npx",
|
|
31
|
+
"args": ["-y", "@yoonion/mimi-seed-mcp"]
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## 첫 사용 전 인증
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npx -y @yoonion/mimi-seed-mcp mimi-seed-auth
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
브라우저가 열리면 Google 계정으로 로그인. 토큰은 `~/.mimi-seed/tokens.json`에 저장되고 자동 갱신됨.
|
|
44
|
+
|
|
45
|
+
플랫폼별 추가 인증 (필요한 것만):
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npx -y @yoonion/mimi-seed-mcp mimi-seed-appstore-auth # App Store Connect (API Key)
|
|
49
|
+
npx -y @yoonion/mimi-seed-mcp mimi-seed-playstore-auth # Google Play 서비스 계정 JSON
|
|
50
|
+
npx -y @yoonion/mimi-seed-mcp mimi-seed-bigquery-auth # BigQuery (Crashlytics export 등)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
- **App Store Connect**: Users and Access → Keys에서 API Key 생성 후 Issuer ID / Key ID / .p8 경로 입력 → `~/.mimi-seed/appstore.json`
|
|
54
|
+
- **Google Play**: Play Console 서비스 계정 JSON 경로 입력 (패키지별 등록)
|
|
55
|
+
- **BigQuery**: Google OAuth 또는 서비스 계정으로 데이터셋 조회 권한 부여
|
|
56
|
+
|
|
57
|
+
AI 기능(릴리즈 노트 생성, 리뷰 답변)을 쓰려면:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
export ANTHROPIC_API_KEY=sk-ant-...
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## 제공 도구 (147개 · 17개 영역)
|
|
66
|
+
|
|
67
|
+
| 영역 | 도구 수 | 주요 도구 |
|
|
68
|
+
|------|---------|-----------|
|
|
69
|
+
| App Store Connect | 31 | `appstore_submit_for_review` / `appstore_upload_screenshot` / `appstore_update_whats_new` / `appstore_create_version` |
|
|
70
|
+
| Google Play | 28 | `playstore_submit_release` / `playstore_promote_release` / `playstore_replace_images` / `playstore_reply_review` / `playstore_verify_service_account` |
|
|
71
|
+
| Firebase | 19 | `firebase_create_android_app` / `firebase_get_android_config` / `firebase_create_ios_app` / `firebase_enable_service` |
|
|
72
|
+
| AdMob | 7 | `admob_list_apps` / `admob_create_ad_unit` / `admob_get_today_earnings` / `admob_get_report` |
|
|
73
|
+
| CI/CD (GitHub Actions · GitLab) | 6 | `ci_trigger_build` / `ci_get_build_status` / `ci_list_workflows` / `ci_cancel_build` |
|
|
74
|
+
| Jenkins (크리덴셜) | 6 | `jenkins_create_credential` / `jenkins_upload_keystore` / `jenkins_save_config` |
|
|
75
|
+
| GA4 | 6 | `ga4_create_property` / `ga4_create_data_stream` / `ga4_run_report` |
|
|
76
|
+
| Search Console | 6 | `gsc_inspect_url` / `gsc_search_analytics` / `gsc_submit_sitemap` |
|
|
77
|
+
| Google Ads | 6 | `googleads_list_campaigns` / `googleads_get_uac_report` / `googleads_get_campaign_report` |
|
|
78
|
+
| Facebook | 6 | `facebook_post_photo` / `facebook_post_multi_photo` / `facebook_list_pages` |
|
|
79
|
+
| Google Cloud IAM | 5 | `iam_create_service_account` / `iam_create_key` / `iam_add_iam_policy_binding` |
|
|
80
|
+
| BigQuery | 5 | `bigquery_run_query` / `bigquery_list_datasets` / `bigquery_get_table_schema` |
|
|
81
|
+
| 점검 / 위험 | 4 | `playstore_check_submission_risks` / `appstore_check_submission_risks` / `screenshot_validate` / `release_status` |
|
|
82
|
+
| Instagram | 4 | `instagram_post_image` / `instagram_post_carousel` / `instagram_save_config` |
|
|
83
|
+
| Android 서명 | 3 | `android_signing_setup` / `android_generate_keystore` / `jenkins_upload_playstore_sa` |
|
|
84
|
+
| 인증 | 3 | `mimi_seed_status` / `mimi_seed_auth_start` / `mimi_seed_auth_status` |
|
|
85
|
+
| AI (Claude) | 2 | `generate_release_notes_from_commits` / `generate_review_reply` |
|
|
86
|
+
|
|
87
|
+
> 인앱 결제(IAP·구독) 도구는 위 Play Store·App Store 카운트에 포함됩니다 — `playstore_create_subscription` · `appstore_create_inapp_purchase` 등 (`@onesub/providers` 위임).
|
|
88
|
+
> 전체 카탈로그(항상 최신): [`docs/domain/tool-catalog.md`](../../docs/domain/tool-catalog.md)
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## 슬래시 커맨드 (MCP Prompts)
|
|
93
|
+
|
|
94
|
+
MCP 클라이언트(Claude Code, Codex 등)에서 슬래시 커맨드로 바로 노출됩니다.
|
|
95
|
+
|
|
96
|
+
| 커맨드 | 설명 |
|
|
97
|
+
|--------|------|
|
|
98
|
+
| `/mimi-seed:deploy` | 블로커 점검 → 릴리즈 노트 생성 → 스토어 적용을 한 번에 |
|
|
99
|
+
| `/mimi-seed:health` | 인증 상태 + 앱 출시 준비도 빠른 요약 |
|
|
100
|
+
| `/mimi-seed:review-inbox` | 미답변 리뷰 조회 → AI 답변 초안 생성 |
|
|
101
|
+
|
|
102
|
+
## MCP Resources
|
|
103
|
+
|
|
104
|
+
| URI | 설명 |
|
|
105
|
+
|-----|------|
|
|
106
|
+
| `mimi-seed://auth/status` | Google OAuth 토큰 상태 (JSON) |
|
|
107
|
+
| `mimi-seed://agent/guide` | 에이전트 역할 정의 — 출시 워크플로우·주의사항 (Markdown) |
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## 주요 기능
|
|
112
|
+
|
|
113
|
+
### 제출 위험 점검
|
|
114
|
+
|
|
115
|
+
출시 전 블로커와 경고를 자동으로 점검합니다.
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
"내 앱 출시 전 위험 요소 확인해줘"
|
|
119
|
+
→ playstore_check_submission_risks("com.example.myapp")
|
|
120
|
+
→ appstore_check_submission_risks("1234567890")
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**점검 항목:**
|
|
124
|
+
- Google Play: 리스팅 완성도(제목/설명/짧은설명), 스크린샷 수, 아이콘, 내부 빌드 존재, 연락처
|
|
125
|
+
- App Store: What's New, 설명/키워드, 스크린샷 커버리지, TestFlight 빌드, 개인정보처리방침 URL
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
### 스크린샷 해상도 검증
|
|
130
|
+
|
|
131
|
+
업로드 전 로컬 파일을 스토어 규격과 비교합니다.
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
"이 스크린샷들이 App Store 규격에 맞는지 확인해줘"
|
|
135
|
+
→ screenshot_validate(["/path/to/screen1.png", "/path/to/screen2.png"], platform="ios", displayType="APP_IPHONE_69")
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
iOS displayType 예시: `APP_IPHONE_69`, `APP_IPHONE_67`, `APP_IPHONE_65`, `APP_IPAD_PRO_3GEN_129`
|
|
139
|
+
Android imageType 예시: `phoneScreenshots`, `sevenInchScreenshots`, `featureGraphic`
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
### AI 릴리즈 노트 생성 (ANTHROPIC_API_KEY 필요)
|
|
144
|
+
|
|
145
|
+
git 커밋 내역을 Claude가 사용자 친화적인 릴리즈 노트로 변환합니다.
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
"최근 커밋으로 릴리즈 노트 만들어줘"
|
|
149
|
+
→ generate_release_notes_from_commits(
|
|
150
|
+
commits=[{message: "feat: 다크모드 추가"}, ...],
|
|
151
|
+
appName="MyApp",
|
|
152
|
+
locales=["ko", "en-US", "ja"]
|
|
153
|
+
)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
3가지 톤(간결/상세/마케팅) + 다국어를 한 번에 생성. 이후 `playstore_update_release_notes` 또는 `appstore_update_whats_new`로 바로 적용.
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
### AI 리뷰 답변 생성 (ANTHROPIC_API_KEY 필요)
|
|
161
|
+
|
|
162
|
+
스토어 리뷰에 대한 AI 답변 초안을 생성합니다.
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
"이 리뷰에 답변 작성해줘"
|
|
166
|
+
→ generate_review_reply(
|
|
167
|
+
reviewText="앱이 자꾸 튕겨요",
|
|
168
|
+
rating=2,
|
|
169
|
+
appName="MyApp",
|
|
170
|
+
tone="empathetic",
|
|
171
|
+
language="ko"
|
|
172
|
+
)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
tone 옵션: `friendly`(친근) / `professional`(정중) / `empathetic`(공감) / `brief`(간결)
|
|
176
|
+
|
|
177
|
+
> ⚠ AI 생성 답변은 초안입니다. 게시 전 반드시 검토하세요.
|
|
178
|
+
> 답변 게시는 `playstore_reply_review` 도구를 사용하세요.
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## End-to-end: 서비스 계정 → JSON 키 → Play Console 권한
|
|
183
|
+
|
|
184
|
+
서버(예: [onesub](https://github.com/jeonghwanko/onesub))가 Google Play 영수증을 백그라운드로 검증하려면 서비스 계정 JSON이 필요합니다. Claude에게 한 번에 시킬 수 있어요:
|
|
185
|
+
|
|
186
|
+
> 1. `my-project`에 `onesub-play-verifier` 서비스 계정 만들고
|
|
187
|
+
> 2. JSON 키 발급받아서
|
|
188
|
+
> 3. `com.yourapp.id`에 대해 검증
|
|
189
|
+
|
|
190
|
+
Claude가 연쇄 호출:
|
|
191
|
+
|
|
192
|
+
- `iam_create_service_account("my-project", "onesub-play-verifier", "onesub Play verifier")`
|
|
193
|
+
- `iam_create_key("onesub-play-verifier@my-project.iam.gserviceaccount.com")` → JSON 반환
|
|
194
|
+
- `playstore_verify_service_account(<json>, "com.yourapp.id")` → 아직 Play Console 권한이 없어서 403 반환 기대
|
|
195
|
+
|
|
196
|
+
그 다음 **Play Console에서 수동으로** (또는 별도 androidpublisher.users API 호출):
|
|
197
|
+
|
|
198
|
+
- Users and permissions → 서비스 계정 이메일 초대
|
|
199
|
+
- **View financial data, orders, and cancellation survey responses** 체크
|
|
200
|
+
- **~5분 대기** 후 `playstore_verify_service_account` 재실행 → ✓
|
|
201
|
+
|
|
202
|
+
마지막으로 JSON을 `GOOGLE_SERVICE_ACCOUNT_KEY` 서버 env에 넣으면 Play 영수증 검증 가능.
|
|
203
|
+
|
|
204
|
+
> Cloud IAM 역할과 Play Console 권한은 다릅니다. `iam_add_iam_policy_binding`은 Cloud IAM 역할(예: `roles/iam.serviceAccountTokenCreator`)만 부여 — Play Console의 "View financial data"는 별도.
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## 환경변수
|
|
209
|
+
|
|
210
|
+
| 변수 | 설명 |
|
|
211
|
+
|------|------|
|
|
212
|
+
| `ANTHROPIC_API_KEY` | AI 릴리즈 노트 생성 / 리뷰 답변 활성화 (선택) |
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## 레거시 호환성
|
|
217
|
+
|
|
218
|
+
Preseed 시절(`~/.preseed/`) 데이터는 자동으로 이어받음:
|
|
219
|
+
|
|
220
|
+
- `~/.preseed/tokens.json` 있으면 읽음 (재인증 불필요)
|
|
221
|
+
- `~/.preseed/appstore.json`도 동일
|
|
222
|
+
- 환경변수 `PRESEED_GOOGLE_CLIENT_ID` / `PRESEED_GOOGLE_CLIENT_SECRET` 계속 인식
|
|
223
|
+
|
|
224
|
+
새로 쓰는 건 `~/.mimi-seed/`.
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Links
|
|
229
|
+
|
|
230
|
+
- CLI 패키지: [`mimi-seed`](https://www.npmjs.com/package/mimi-seed)
|
|
231
|
+
- 웹 콘솔: <https://mimi-seed.pryzm.gg/tool>
|
|
232
|
+
- 저장소: <https://github.com/jeonghwanko/mimi-seed>
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## License
|
|
237
|
+
|
|
238
|
+
[PolyForm Noncommercial License 1.0.0](../../LICENSE) — 비상업적 사용만 허용.
|
|
239
|
+
상업적 이용 문의: turbo08@gmail.com
|
|
240
|
+
|
|
241
|
+
**Required Notice:** Copyright 2026 Pryzm GG (https://mimi-seed.pryzm.gg)
|
package/dist/admob/cli.js
CHANGED
|
@@ -5,26 +5,26 @@
|
|
|
5
5
|
import { requireAuth } from '../helpers.js';
|
|
6
6
|
import * as admob from './tools.js';
|
|
7
7
|
import { runDomainCli, requireFlag, flag, CliUsageError } from '../lib/cli-args.js';
|
|
8
|
-
const HELP = `
|
|
9
|
-
💰 mimi-seed-admob — AdMob attach
|
|
10
|
-
|
|
11
|
-
사용법:
|
|
12
|
-
mimi-seed admob accounts
|
|
13
|
-
AdMob 계정 목록 (accountId 확인 — accounts/pub-XXXX)
|
|
14
|
-
|
|
15
|
-
mimi-seed admob apps --account <id>
|
|
16
|
-
mimi-seed admob ad-units --account <id>
|
|
17
|
-
등록된 앱 / 광고 단위 목록
|
|
18
|
-
|
|
19
|
-
mimi-seed admob create-app --account <id> --platform <ANDROID|IOS> --name <displayName>
|
|
20
|
-
[--store-id com.x.y | 123456789]
|
|
21
|
-
앱 등록 (store-id 주면 스토어 링크). ⚠️ v1beta Limited Access — 403 가능
|
|
22
|
-
|
|
23
|
-
mimi-seed admob create-ad-unit --account <id> --app <appId> --name <name>
|
|
24
|
-
--format <BANNER|INTERSTITIAL|REWARDED|REWARDED_INTERSTITIAL|APP_OPEN|NATIVE>
|
|
25
|
-
광고 단위 생성. ⚠️ v1beta Limited Access — 403 가능
|
|
26
|
-
|
|
27
|
-
인증: npx -y @yoonion/mimi-seed-mcp mimi-seed-auth
|
|
8
|
+
const HELP = `
|
|
9
|
+
💰 mimi-seed-admob — AdMob attach
|
|
10
|
+
|
|
11
|
+
사용법:
|
|
12
|
+
mimi-seed admob accounts
|
|
13
|
+
AdMob 계정 목록 (accountId 확인 — accounts/pub-XXXX)
|
|
14
|
+
|
|
15
|
+
mimi-seed admob apps --account <id>
|
|
16
|
+
mimi-seed admob ad-units --account <id>
|
|
17
|
+
등록된 앱 / 광고 단위 목록
|
|
18
|
+
|
|
19
|
+
mimi-seed admob create-app --account <id> --platform <ANDROID|IOS> --name <displayName>
|
|
20
|
+
[--store-id com.x.y | 123456789]
|
|
21
|
+
앱 등록 (store-id 주면 스토어 링크). ⚠️ v1beta Limited Access — 403 가능
|
|
22
|
+
|
|
23
|
+
mimi-seed admob create-ad-unit --account <id> --app <appId> --name <name>
|
|
24
|
+
--format <BANNER|INTERSTITIAL|REWARDED|REWARDED_INTERSTITIAL|APP_OPEN|NATIVE>
|
|
25
|
+
광고 단위 생성. ⚠️ v1beta Limited Access — 403 가능
|
|
26
|
+
|
|
27
|
+
인증: npx -y @yoonion/mimi-seed-mcp mimi-seed-auth
|
|
28
28
|
`;
|
|
29
29
|
const AD_FORMATS = ['BANNER', 'INTERSTITIAL', 'REWARDED', 'REWARDED_INTERSTITIAL', 'APP_OPEN', 'NATIVE'];
|
|
30
30
|
runDomainCli({
|
package/dist/auth/google-auth.js
CHANGED
|
@@ -215,13 +215,13 @@ export function startAuth(clientId, clientSecret, options = {}) {
|
|
|
215
215
|
};
|
|
216
216
|
saveTokens(stored);
|
|
217
217
|
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
218
|
-
res.end(`
|
|
219
|
-
<html><body style="font-family:system-ui;display:flex;justify-content:center;align-items:center;height:100vh;margin:0">
|
|
220
|
-
<div style="text-align:center">
|
|
221
|
-
<h1>✅ Mimi Seed 인증 완료!</h1>
|
|
222
|
-
<p>이 창을 닫고 Claude Code 또는 Codex로 돌아가세요.</p>
|
|
223
|
-
</div>
|
|
224
|
-
</body></html>
|
|
218
|
+
res.end(`
|
|
219
|
+
<html><body style="font-family:system-ui;display:flex;justify-content:center;align-items:center;height:100vh;margin:0">
|
|
220
|
+
<div style="text-align:center">
|
|
221
|
+
<h1>✅ Mimi Seed 인증 완료!</h1>
|
|
222
|
+
<p>이 창을 닫고 Claude Code 또는 Codex로 돌아가세요.</p>
|
|
223
|
+
</div>
|
|
224
|
+
</body></html>
|
|
225
225
|
`);
|
|
226
226
|
server.close();
|
|
227
227
|
activeAuthServer = null;
|
package/dist/firebase/cli.js
CHANGED
|
@@ -5,33 +5,33 @@ import { requireAuth } from '../helpers.js';
|
|
|
5
5
|
import * as firebase from './tools.js';
|
|
6
6
|
import { runDomainCli, requireFlag, flag, CliUsageError } from '../lib/cli-args.js';
|
|
7
7
|
const FB_PLATFORMS = ['android', 'ios', 'web'];
|
|
8
|
-
const HELP = `
|
|
9
|
-
🔥 mimi-seed-firebase — Firebase attach (프로비저닝 + config 산출)
|
|
10
|
-
|
|
11
|
-
사용법:
|
|
12
|
-
mimi-seed firebase projects
|
|
13
|
-
내 Firebase 프로젝트 목록
|
|
14
|
-
|
|
15
|
-
mimi-seed firebase apps --project <id> [--platform android|ios|web]
|
|
16
|
-
프로젝트의 앱 목록 (기본: android+ios+web 전부)
|
|
17
|
-
|
|
18
|
-
mimi-seed firebase create-android --project <id> --package com.x.y --name <displayName>
|
|
19
|
-
mimi-seed firebase create-ios --project <id> --bundle com.x.y --name <displayName>
|
|
20
|
-
새 앱 등록
|
|
21
|
-
|
|
22
|
-
mimi-seed firebase config --project <id> --app <appId> --platform <android|ios|web>
|
|
23
|
-
⭐ google-services.json / GoogleService-Info.plist / web config 출력 (attach 페이로드)
|
|
24
|
-
|
|
25
|
-
mimi-seed firebase enable-services --project <id>
|
|
26
|
-
Firebase 기본 서비스 일괄 활성화 (Analytics 포함)
|
|
27
|
-
|
|
28
|
-
mimi-seed firebase link-analytics --project <id> (--account <gaAccountId> | --property <gaPropertyId>)
|
|
29
|
-
GA4 링크 (앱 measurement 자동 활성화) — account(신규 property 생성) 또는 property(기존 연결) 중 하나 필수
|
|
30
|
-
|
|
31
|
-
mimi-seed firebase analytics-details --project <id>
|
|
32
|
-
GA4 링크 상세 (property + stream 매핑)
|
|
33
|
-
|
|
34
|
-
인증: npx -y @yoonion/mimi-seed-mcp mimi-seed-auth
|
|
8
|
+
const HELP = `
|
|
9
|
+
🔥 mimi-seed-firebase — Firebase attach (프로비저닝 + config 산출)
|
|
10
|
+
|
|
11
|
+
사용법:
|
|
12
|
+
mimi-seed firebase projects
|
|
13
|
+
내 Firebase 프로젝트 목록
|
|
14
|
+
|
|
15
|
+
mimi-seed firebase apps --project <id> [--platform android|ios|web]
|
|
16
|
+
프로젝트의 앱 목록 (기본: android+ios+web 전부)
|
|
17
|
+
|
|
18
|
+
mimi-seed firebase create-android --project <id> --package com.x.y --name <displayName>
|
|
19
|
+
mimi-seed firebase create-ios --project <id> --bundle com.x.y --name <displayName>
|
|
20
|
+
새 앱 등록
|
|
21
|
+
|
|
22
|
+
mimi-seed firebase config --project <id> --app <appId> --platform <android|ios|web>
|
|
23
|
+
⭐ google-services.json / GoogleService-Info.plist / web config 출력 (attach 페이로드)
|
|
24
|
+
|
|
25
|
+
mimi-seed firebase enable-services --project <id>
|
|
26
|
+
Firebase 기본 서비스 일괄 활성화 (Analytics 포함)
|
|
27
|
+
|
|
28
|
+
mimi-seed firebase link-analytics --project <id> (--account <gaAccountId> | --property <gaPropertyId>)
|
|
29
|
+
GA4 링크 (앱 measurement 자동 활성화) — account(신규 property 생성) 또는 property(기존 연결) 중 하나 필수
|
|
30
|
+
|
|
31
|
+
mimi-seed firebase analytics-details --project <id>
|
|
32
|
+
GA4 링크 상세 (property + stream 매핑)
|
|
33
|
+
|
|
34
|
+
인증: npx -y @yoonion/mimi-seed-mcp mimi-seed-auth
|
|
35
35
|
`;
|
|
36
36
|
async function listApps(projectId, platform) {
|
|
37
37
|
const auth = await requireAuth();
|
package/dist/ga4/cli.js
CHANGED
|
@@ -4,33 +4,33 @@
|
|
|
4
4
|
import { requireAuth } from '../helpers.js';
|
|
5
5
|
import * as ga4 from './tools.js';
|
|
6
6
|
import { runDomainCli, requireFlag, flag, flagList } from '../lib/cli-args.js';
|
|
7
|
-
const HELP = `
|
|
8
|
-
📊 mimi-seed-ga4 — GA4(Google Analytics 4) attach
|
|
9
|
-
|
|
10
|
-
사용법:
|
|
11
|
-
mimi-seed ga4 accounts
|
|
12
|
-
접근 가능한 GA 계정 + property 요약 (accountId/propertyId 확인)
|
|
13
|
-
|
|
14
|
-
mimi-seed ga4 properties --account <id>
|
|
15
|
-
계정 하위 GA4 property 목록
|
|
16
|
-
|
|
17
|
-
mimi-seed ga4 create-property --account <id> --name <displayName>
|
|
18
|
-
[--timezone Asia/Seoul] [--currency KRW]
|
|
19
|
-
새 GA4 property 생성
|
|
20
|
-
|
|
21
|
-
mimi-seed ga4 create-stream --property <id> --platform <web|android|ios> --name <name>
|
|
22
|
-
[--uri https://...] [--package com.x.y] [--bundle com.x.y]
|
|
23
|
-
data stream 생성 (web→measurementId, app→firebaseAppId)
|
|
24
|
-
|
|
25
|
-
mimi-seed ga4 streams --property <id>
|
|
26
|
-
data stream 목록
|
|
27
|
-
|
|
28
|
-
mimi-seed ga4 report --property <id> --start 28daysAgo --end today
|
|
29
|
-
[--dimensions date,country] [--metrics activeUsers,eventCount]
|
|
30
|
-
GA4 Data API 리포트
|
|
31
|
-
|
|
32
|
-
⚠️ analytics.edit 스코프 필요 — 처음이면 재로그인:
|
|
33
|
-
npx -y @yoonion/mimi-seed-mcp mimi-seed-auth
|
|
7
|
+
const HELP = `
|
|
8
|
+
📊 mimi-seed-ga4 — GA4(Google Analytics 4) attach
|
|
9
|
+
|
|
10
|
+
사용법:
|
|
11
|
+
mimi-seed ga4 accounts
|
|
12
|
+
접근 가능한 GA 계정 + property 요약 (accountId/propertyId 확인)
|
|
13
|
+
|
|
14
|
+
mimi-seed ga4 properties --account <id>
|
|
15
|
+
계정 하위 GA4 property 목록
|
|
16
|
+
|
|
17
|
+
mimi-seed ga4 create-property --account <id> --name <displayName>
|
|
18
|
+
[--timezone Asia/Seoul] [--currency KRW]
|
|
19
|
+
새 GA4 property 생성
|
|
20
|
+
|
|
21
|
+
mimi-seed ga4 create-stream --property <id> --platform <web|android|ios> --name <name>
|
|
22
|
+
[--uri https://...] [--package com.x.y] [--bundle com.x.y]
|
|
23
|
+
data stream 생성 (web→measurementId, app→firebaseAppId)
|
|
24
|
+
|
|
25
|
+
mimi-seed ga4 streams --property <id>
|
|
26
|
+
data stream 목록
|
|
27
|
+
|
|
28
|
+
mimi-seed ga4 report --property <id> --start 28daysAgo --end today
|
|
29
|
+
[--dimensions date,country] [--metrics activeUsers,eventCount]
|
|
30
|
+
GA4 Data API 리포트
|
|
31
|
+
|
|
32
|
+
⚠️ analytics.edit 스코프 필요 — 처음이면 재로그인:
|
|
33
|
+
npx -y @yoonion/mimi-seed-mcp mimi-seed-auth
|
|
34
34
|
`;
|
|
35
35
|
runDomainCli({
|
|
36
36
|
binName: 'mimi-seed-ga4',
|
package/dist/googleads/tools.js
CHANGED
|
@@ -84,20 +84,20 @@ export async function listAccessibleCustomers(auth, cfg) {
|
|
|
84
84
|
}
|
|
85
85
|
// ─── 캠페인 목록 ─────────────────────────────────────────────
|
|
86
86
|
export async function listCampaigns(auth, cfg) {
|
|
87
|
-
const query = `
|
|
88
|
-
SELECT
|
|
89
|
-
campaign.id,
|
|
90
|
-
campaign.name,
|
|
91
|
-
campaign.status,
|
|
92
|
-
campaign.advertising_channel_type,
|
|
93
|
-
campaign.advertising_channel_sub_type,
|
|
94
|
-
campaign.start_date,
|
|
95
|
-
campaign.end_date,
|
|
96
|
-
campaign_budget.amount_micros
|
|
97
|
-
FROM campaign
|
|
98
|
-
WHERE campaign.status != 'REMOVED'
|
|
99
|
-
ORDER BY campaign.name ASC
|
|
100
|
-
LIMIT 200
|
|
87
|
+
const query = `
|
|
88
|
+
SELECT
|
|
89
|
+
campaign.id,
|
|
90
|
+
campaign.name,
|
|
91
|
+
campaign.status,
|
|
92
|
+
campaign.advertising_channel_type,
|
|
93
|
+
campaign.advertising_channel_sub_type,
|
|
94
|
+
campaign.start_date,
|
|
95
|
+
campaign.end_date,
|
|
96
|
+
campaign_budget.amount_micros
|
|
97
|
+
FROM campaign
|
|
98
|
+
WHERE campaign.status != 'REMOVED'
|
|
99
|
+
ORDER BY campaign.name ASC
|
|
100
|
+
LIMIT 200
|
|
101
101
|
`;
|
|
102
102
|
const rows = await search(auth, cfg, query);
|
|
103
103
|
return rows.map((r) => ({
|
|
@@ -113,26 +113,26 @@ export async function listCampaigns(auth, cfg) {
|
|
|
113
113
|
}
|
|
114
114
|
// ─── 캠페인 성과 리포트 ────────────────────────────────────────
|
|
115
115
|
export async function getCampaignReport(auth, cfg, range) {
|
|
116
|
-
const query = `
|
|
117
|
-
SELECT
|
|
118
|
-
campaign.id,
|
|
119
|
-
campaign.name,
|
|
120
|
-
campaign.status,
|
|
121
|
-
campaign.advertising_channel_type,
|
|
122
|
-
campaign.advertising_channel_sub_type,
|
|
123
|
-
metrics.clicks,
|
|
124
|
-
metrics.impressions,
|
|
125
|
-
metrics.cost_micros,
|
|
126
|
-
metrics.conversions,
|
|
127
|
-
metrics.conversions_value,
|
|
128
|
-
metrics.cost_per_conversion,
|
|
129
|
-
metrics.ctr,
|
|
130
|
-
metrics.average_cpc
|
|
131
|
-
FROM campaign
|
|
132
|
-
WHERE campaign.status != 'REMOVED'
|
|
133
|
-
AND segments.date BETWEEN '${range.startDate}' AND '${range.endDate}'
|
|
134
|
-
ORDER BY metrics.cost_micros DESC
|
|
135
|
-
LIMIT 500
|
|
116
|
+
const query = `
|
|
117
|
+
SELECT
|
|
118
|
+
campaign.id,
|
|
119
|
+
campaign.name,
|
|
120
|
+
campaign.status,
|
|
121
|
+
campaign.advertising_channel_type,
|
|
122
|
+
campaign.advertising_channel_sub_type,
|
|
123
|
+
metrics.clicks,
|
|
124
|
+
metrics.impressions,
|
|
125
|
+
metrics.cost_micros,
|
|
126
|
+
metrics.conversions,
|
|
127
|
+
metrics.conversions_value,
|
|
128
|
+
metrics.cost_per_conversion,
|
|
129
|
+
metrics.ctr,
|
|
130
|
+
metrics.average_cpc
|
|
131
|
+
FROM campaign
|
|
132
|
+
WHERE campaign.status != 'REMOVED'
|
|
133
|
+
AND segments.date BETWEEN '${range.startDate}' AND '${range.endDate}'
|
|
134
|
+
ORDER BY metrics.cost_micros DESC
|
|
135
|
+
LIMIT 500
|
|
136
136
|
`;
|
|
137
137
|
const rows = await search(auth, cfg, query);
|
|
138
138
|
return rows.map((r) => ({
|
|
@@ -153,26 +153,26 @@ export async function getCampaignReport(auth, cfg, range) {
|
|
|
153
153
|
}
|
|
154
154
|
// ─── UAC(앱 캠페인) 리포트 ─────────────────────────────────────
|
|
155
155
|
export async function getUacReport(auth, cfg, range) {
|
|
156
|
-
const query = `
|
|
157
|
-
SELECT
|
|
158
|
-
campaign.id,
|
|
159
|
-
campaign.name,
|
|
160
|
-
campaign.status,
|
|
161
|
-
campaign.advertising_channel_sub_type,
|
|
162
|
-
metrics.clicks,
|
|
163
|
-
metrics.impressions,
|
|
164
|
-
metrics.cost_micros,
|
|
165
|
-
metrics.conversions,
|
|
166
|
-
metrics.conversions_value,
|
|
167
|
-
metrics.cost_per_conversion,
|
|
168
|
-
metrics.ctr,
|
|
169
|
-
segments.date
|
|
170
|
-
FROM campaign
|
|
171
|
-
WHERE campaign.advertising_channel_type = 'MULTI_CHANNEL'
|
|
172
|
-
AND campaign.advertising_channel_sub_type IN ('APP_CAMPAIGN', 'APP_CAMPAIGN_FOR_ENGAGEMENT', 'APP_CAMPAIGN_FOR_PRE_REGISTRATION')
|
|
173
|
-
AND segments.date BETWEEN '${range.startDate}' AND '${range.endDate}'
|
|
174
|
-
ORDER BY segments.date DESC, metrics.cost_micros DESC
|
|
175
|
-
LIMIT 500
|
|
156
|
+
const query = `
|
|
157
|
+
SELECT
|
|
158
|
+
campaign.id,
|
|
159
|
+
campaign.name,
|
|
160
|
+
campaign.status,
|
|
161
|
+
campaign.advertising_channel_sub_type,
|
|
162
|
+
metrics.clicks,
|
|
163
|
+
metrics.impressions,
|
|
164
|
+
metrics.cost_micros,
|
|
165
|
+
metrics.conversions,
|
|
166
|
+
metrics.conversions_value,
|
|
167
|
+
metrics.cost_per_conversion,
|
|
168
|
+
metrics.ctr,
|
|
169
|
+
segments.date
|
|
170
|
+
FROM campaign
|
|
171
|
+
WHERE campaign.advertising_channel_type = 'MULTI_CHANNEL'
|
|
172
|
+
AND campaign.advertising_channel_sub_type IN ('APP_CAMPAIGN', 'APP_CAMPAIGN_FOR_ENGAGEMENT', 'APP_CAMPAIGN_FOR_PRE_REGISTRATION')
|
|
173
|
+
AND segments.date BETWEEN '${range.startDate}' AND '${range.endDate}'
|
|
174
|
+
ORDER BY segments.date DESC, metrics.cost_micros DESC
|
|
175
|
+
LIMIT 500
|
|
176
176
|
`;
|
|
177
177
|
const rows = await search(auth, cfg, query);
|
|
178
178
|
const byId = new Map();
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export declare const MANIFEST_FILENAME = ".mimi-seed.json";
|
|
2
|
+
/** 매니페스트가 인지하는 서비스 id. status 매칭 로직이 이 키를 기준으로 동작한다. */
|
|
3
|
+
export type ManifestServiceId = 'oauth' | 'bigquery' | 'playstore' | 'appstore' | 'jenkins';
|
|
4
|
+
export interface ManifestService {
|
|
5
|
+
/** 이 프로젝트에서 필수인지. false(선택)면 미설정이어도 ❌ 대신 정보 표기. */
|
|
6
|
+
required?: boolean;
|
|
7
|
+
/** 사람이 읽을 한 줄 설명. status 출력에 그대로 표시. */
|
|
8
|
+
note?: string;
|
|
9
|
+
projectId?: string;
|
|
10
|
+
dataset?: string;
|
|
11
|
+
packageName?: string;
|
|
12
|
+
keyId?: string;
|
|
13
|
+
issuerId?: string;
|
|
14
|
+
url?: string;
|
|
15
|
+
/** 이 서비스가 워크스페이스 공유 시크릿(provider)으로도 제공되는 경우 그 provider id. */
|
|
16
|
+
workspaceProvider?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface ProjectManifest {
|
|
19
|
+
project?: string;
|
|
20
|
+
displayName?: string;
|
|
21
|
+
description?: string;
|
|
22
|
+
services?: Partial<Record<ManifestServiceId, ManifestService>>;
|
|
23
|
+
}
|
|
24
|
+
export interface LoadedManifest {
|
|
25
|
+
manifest: ProjectManifest;
|
|
26
|
+
/** 실제로 읽은 파일 절대 경로. */
|
|
27
|
+
filePath: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* startDir 에서 위로 올라가며 첫 번째 `.mimi-seed.json` 을 찾는다.
|
|
31
|
+
* MCP stdio 서버의 cwd 는 보통 프로젝트 루트지만, 하위 폴더에서 실행돼도 잡히게 상향 탐색한다.
|
|
32
|
+
* maxDepth 로 홈 디렉터리 밖까지 무한 상승하는 것을 방지.
|
|
33
|
+
*/
|
|
34
|
+
export declare function findProjectManifest(startDir?: string, maxDepth?: number): LoadedManifest | null;
|
|
35
|
+
/** 매니페스트 services 를 [id, service] 배열로. 없으면 빈 배열. */
|
|
36
|
+
export declare function manifestServiceEntries(m: ProjectManifest): Array<[ManifestServiceId, ManifestService]>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// 프로젝트 매니페스트(.mimi-seed.json) 리더.
|
|
2
|
+
//
|
|
3
|
+
// 프로젝트 루트에 커밋된 `.mimi-seed.json` 이 "이 저장소를 mimi-seed 로 다루려면
|
|
4
|
+
// 어떤 서비스 연결이 필요한가"를 선언한다. mimi_seed_status(MCP)와 mimi-seed doctor(CLI)가
|
|
5
|
+
// 이 파일을 읽어, 범용 9종 스캔 대신 "이 프로젝트에서 너한테 빠진 것 + 정확한 셋업 명령"을 보여준다.
|
|
6
|
+
//
|
|
7
|
+
// 팀 온보딩 목적: 새 팀원이 clone → mimi_seed_status 호출 → 안내 따라가기 만으로
|
|
8
|
+
// 자기 머신에 필요한 자격증명을 채울 수 있게 한다.
|
|
9
|
+
import fs from 'node:fs';
|
|
10
|
+
import path from 'node:path';
|
|
11
|
+
export const MANIFEST_FILENAME = '.mimi-seed.json';
|
|
12
|
+
/**
|
|
13
|
+
* startDir 에서 위로 올라가며 첫 번째 `.mimi-seed.json` 을 찾는다.
|
|
14
|
+
* MCP stdio 서버의 cwd 는 보통 프로젝트 루트지만, 하위 폴더에서 실행돼도 잡히게 상향 탐색한다.
|
|
15
|
+
* maxDepth 로 홈 디렉터리 밖까지 무한 상승하는 것을 방지.
|
|
16
|
+
*/
|
|
17
|
+
export function findProjectManifest(startDir = process.cwd(), maxDepth = 8) {
|
|
18
|
+
let dir = path.resolve(startDir);
|
|
19
|
+
for (let i = 0; i <= maxDepth; i++) {
|
|
20
|
+
const candidate = path.join(dir, MANIFEST_FILENAME);
|
|
21
|
+
if (fs.existsSync(candidate)) {
|
|
22
|
+
const parsed = safeParse(candidate);
|
|
23
|
+
if (parsed)
|
|
24
|
+
return { manifest: parsed, filePath: candidate };
|
|
25
|
+
return null; // 파일은 있으나 형식 오류 — 상위로 더 올라가지 않는다(의도 명확).
|
|
26
|
+
}
|
|
27
|
+
const parent = path.dirname(dir);
|
|
28
|
+
if (parent === dir)
|
|
29
|
+
break; // 루트 도달
|
|
30
|
+
dir = parent;
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
function safeParse(filePath) {
|
|
35
|
+
try {
|
|
36
|
+
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
37
|
+
const obj = JSON.parse(raw);
|
|
38
|
+
if (obj && typeof obj === 'object')
|
|
39
|
+
return obj;
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/** 매니페스트 services 를 [id, service] 배열로. 없으면 빈 배열. */
|
|
47
|
+
export function manifestServiceEntries(m) {
|
|
48
|
+
const svc = m.services ?? {};
|
|
49
|
+
return Object.keys(svc)
|
|
50
|
+
.filter((k) => svc[k] != null)
|
|
51
|
+
.map((k) => [k, svc[k]]);
|
|
52
|
+
}
|
package/dist/registers/auth.js
CHANGED
|
@@ -7,7 +7,8 @@ import { loadCiConfig } from '../ci/config.js';
|
|
|
7
7
|
import { loadConfig as loadGoogleAdsConfig } from '../googleads/config.js';
|
|
8
8
|
import { loadFacebookConfig } from '../facebook/config.js';
|
|
9
9
|
import { loadInstagramConfig } from '../instagram/config.js';
|
|
10
|
-
import {
|
|
10
|
+
import { resolveBigQueryAuth } from '../auth/bigquery-auth.js';
|
|
11
|
+
import { findProjectManifest, manifestServiceEntries, } from '../lib/project-manifest.js';
|
|
11
12
|
/**
|
|
12
13
|
* tokens.json mtime → "Nd Hh ago" 형식 문자열 + 재인증 권고.
|
|
13
14
|
* Google 정책: 7일 미사용 시 미인증 앱 refresh_token revoke 가능.
|
|
@@ -34,6 +35,54 @@ function formatLastRefreshHint(lastMs) {
|
|
|
34
35
|
}
|
|
35
36
|
return { label };
|
|
36
37
|
}
|
|
38
|
+
// 매니페스트 서비스별 셋업 명령. status/doctor 가 "정확한 다음 명령"으로 안내한다.
|
|
39
|
+
const MANIFEST_FIX = {
|
|
40
|
+
oauth: () => 'mimi_seed_auth_start (Google 로그인 — Firebase/AdMob/Play/GSC/GA4)',
|
|
41
|
+
bigquery: () => 'npx -y @yoonion/mimi-seed-mcp mimi-seed-bigquery-auth (서비스 계정 권장)',
|
|
42
|
+
playstore: (svc) => svc.packageName
|
|
43
|
+
? `setup_playstore_connection(packageName="${svc.packageName}")`
|
|
44
|
+
: 'setup_playstore_connection(packageName=...)',
|
|
45
|
+
appstore: () => 'npx -y @yoonion/mimi-seed-mcp mimi-seed-appstore-auth',
|
|
46
|
+
jenkins: () => 'claude mcp add virgm-jenkins -s user (개인 자격증명 — .mcp.json 금지)',
|
|
47
|
+
};
|
|
48
|
+
/** 서비스별 식별자를 한 줄 detail 로 (예: "ads-coffee / analytics_530080532"). */
|
|
49
|
+
function manifestServiceDetail(id, svc) {
|
|
50
|
+
const parts = [];
|
|
51
|
+
if (id === 'bigquery') {
|
|
52
|
+
if (svc.projectId)
|
|
53
|
+
parts.push(svc.projectId);
|
|
54
|
+
if (svc.dataset)
|
|
55
|
+
parts.push(svc.dataset);
|
|
56
|
+
}
|
|
57
|
+
else if (id === 'playstore') {
|
|
58
|
+
if (svc.packageName)
|
|
59
|
+
parts.push(svc.packageName);
|
|
60
|
+
}
|
|
61
|
+
else if (id === 'appstore') {
|
|
62
|
+
if (svc.keyId)
|
|
63
|
+
parts.push(`keyId ${svc.keyId}`);
|
|
64
|
+
}
|
|
65
|
+
else if (id === 'jenkins') {
|
|
66
|
+
if (svc.url)
|
|
67
|
+
parts.push(svc.url);
|
|
68
|
+
}
|
|
69
|
+
return parts.join(' / ');
|
|
70
|
+
}
|
|
71
|
+
/** 매니페스트 한 서비스를 status 라인(들)으로 렌더. 미설정+필수면 명령 힌트를 붙인다. */
|
|
72
|
+
function renderManifestLine(id, svc, connected, required) {
|
|
73
|
+
const label = id.padEnd(10);
|
|
74
|
+
const detail = manifestServiceDetail(id, svc);
|
|
75
|
+
const detailSuffix = detail ? ` (${detail})` : '';
|
|
76
|
+
if (connected)
|
|
77
|
+
return `✅ ${label} — 연결됨${detailSuffix}`;
|
|
78
|
+
if (!required) {
|
|
79
|
+
const note = svc.note ? ` — ${svc.note}` : '';
|
|
80
|
+
return `ℹ️ ${label} — (선택)${detailSuffix}${note}`;
|
|
81
|
+
}
|
|
82
|
+
const fix = MANIFEST_FIX[id](svc);
|
|
83
|
+
const noteLine = svc.note ? `\n ${svc.note}` : '';
|
|
84
|
+
return `❌ ${label} — 미설정${detailSuffix}\n → ${fix}${noteLine}`;
|
|
85
|
+
}
|
|
37
86
|
export function registerAuthTools(server) {
|
|
38
87
|
// ── 전체 연결 상태 진단 ────────────────────────────────────────────────────
|
|
39
88
|
server.tool('mimi_seed_status', [
|
|
@@ -114,10 +163,14 @@ export function registerAuthTools(server) {
|
|
|
114
163
|
else {
|
|
115
164
|
lines.push('❌ Instagram — 미설정 → instagram_save_config (선택)');
|
|
116
165
|
}
|
|
117
|
-
// 9. BigQuery
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
166
|
+
// 9. BigQuery — resolveBigQueryAuth 기준(서비스 계정 우선, OAuth fallback).
|
|
167
|
+
// 이전엔 SA 파일만 검사해 OAuth fallback 이 살아있어도 ❌ 로 오표기했다.
|
|
168
|
+
const bqAuth = resolveBigQueryAuth();
|
|
169
|
+
if (bqAuth?.source === 'service-account') {
|
|
170
|
+
lines.push(`✅ BigQuery — 서비스 계정 연결됨 (${bqAuth.clientEmail ?? ''})`);
|
|
171
|
+
}
|
|
172
|
+
else if (bqAuth?.source === 'user-oauth') {
|
|
173
|
+
lines.push('⚠️ BigQuery — OAuth fallback (Workspace 재인증 정책 시 끊길 수 있음 → 서비스 계정 권장: mimi-seed-bigquery-auth)');
|
|
121
174
|
}
|
|
122
175
|
else {
|
|
123
176
|
lines.push('❌ BigQuery — 미설정 → npx @yoonion/mimi-seed-mcp mimi-seed-bigquery-auth (선택)');
|
|
@@ -139,6 +192,36 @@ export function registerAuthTools(server) {
|
|
|
139
192
|
else {
|
|
140
193
|
lines.push('', '✅ 필수 연결 모두 완료. 앱 출시 작업을 시작할 수 있습니다.');
|
|
141
194
|
}
|
|
195
|
+
// ── 프로젝트 매니페스트(.mimi-seed.json) 기반 요구사항 ────────────────────
|
|
196
|
+
// 이 저장소가 "무엇을 필요로 하는가"를 선언해두면, 범용 스캔 대신
|
|
197
|
+
// "이 프로젝트에서 너한테 빠진 것 + 정확한 셋업 명령"을 팀원별로 보여준다.
|
|
198
|
+
const loaded = findProjectManifest();
|
|
199
|
+
if (loaded) {
|
|
200
|
+
const oauthOk = oauthResult.status === 'fresh' || oauthResult.status === 'refreshed';
|
|
201
|
+
const playstoreCovers = (pkg) => saCount > 0 &&
|
|
202
|
+
(!pkg || !!saInfo.default || saInfo.perPackage.some((p) => p.packageName === pkg));
|
|
203
|
+
const state = {
|
|
204
|
+
oauth: oauthOk,
|
|
205
|
+
bigquery: !!bqAuth,
|
|
206
|
+
playstore: playstoreCovers(),
|
|
207
|
+
appstore: !!asc,
|
|
208
|
+
jenkins: !!jenkins,
|
|
209
|
+
};
|
|
210
|
+
const projName = loaded.manifest.displayName ?? loaded.manifest.project ?? '이 프로젝트';
|
|
211
|
+
const reqLines = ['', `── ${projName} 요구사항 (.mimi-seed.json) ─────────`];
|
|
212
|
+
let anyMissing = false;
|
|
213
|
+
for (const [id, svc] of manifestServiceEntries(loaded.manifest)) {
|
|
214
|
+
const required = svc.required !== false;
|
|
215
|
+
const connected = id === 'playstore' ? playstoreCovers(svc.packageName) : state[id];
|
|
216
|
+
reqLines.push(renderManifestLine(id, svc, connected, required));
|
|
217
|
+
if (required && !connected)
|
|
218
|
+
anyMissing = true;
|
|
219
|
+
}
|
|
220
|
+
if (anyMissing) {
|
|
221
|
+
reqLines.push('', 'ℹ️ 팀 공유가 목표라면, 각자 로컬 자격증명을 채우는 대신', ' 워크스페이스(https://mimi-seed.pryzm.gg) 초대 → PAT 발급 → 원격 MCP 연결도 가능.');
|
|
222
|
+
}
|
|
223
|
+
lines.push(...reqLines);
|
|
224
|
+
}
|
|
142
225
|
return { content: [{ type: 'text', text: lines.join('\n') }] };
|
|
143
226
|
});
|
|
144
227
|
server.tool('mimi_seed_auth_start', [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yoonion/mimi-seed-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.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": {
|
|
@@ -50,6 +50,9 @@
|
|
|
50
50
|
"engines": {
|
|
51
51
|
"node": ">=20"
|
|
52
52
|
},
|
|
53
|
+
"overrides": {
|
|
54
|
+
"gaxios": "7.1.5"
|
|
55
|
+
},
|
|
53
56
|
"dependencies": {
|
|
54
57
|
"@anthropic-ai/sdk": "^0.52.0",
|
|
55
58
|
"@modelcontextprotocol/sdk": "^1.12.1",
|