@yoonion/mimi-seed-mcp 0.6.1 → 0.6.3

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
@@ -9,13 +9,13 @@
9
9
  Claude Code:
10
10
 
11
11
  ```bash
12
- claude mcp add mimi-seed -- npx -y @yoonion/mimi-seed-mcp
12
+ claude mcp add mimi-seed-local -- npx -y @yoonion/mimi-seed-mcp
13
13
  ```
14
14
 
15
15
  Codex (`~/.codex/config.toml`):
16
16
 
17
17
  ```toml
18
- [mcp_servers.mimi-seed]
18
+ [mcp_servers.mimi-seed-local]
19
19
  command = "npx"
20
20
  args = ["-y", "@yoonion/mimi-seed-mcp"]
21
21
  enabled = true
@@ -26,7 +26,7 @@ Claude Desktop (`claude_desktop_config.json`):
26
26
  ```json
27
27
  {
28
28
  "mcpServers": {
29
- "mimi-seed": {
29
+ "mimi-seed-local": {
30
30
  "command": "npx",
31
31
  "args": ["-y", "@yoonion/mimi-seed-mcp"]
32
32
  }
@@ -62,7 +62,7 @@ export ANTHROPIC_API_KEY=sk-ant-...
62
62
 
63
63
  ---
64
64
 
65
- ## 제공 도구 (148개 · 17개 영역)
65
+ ## 제공 도구 (150+ 개 · 17개 영역)
66
66
 
67
67
  | 영역 | 도구 수 | 주요 도구 |
68
68
  |------|---------|-----------|
@@ -71,7 +71,7 @@ export ANTHROPIC_API_KEY=sk-ant-...
71
71
  | Firebase | 20 | `firebase_create_project` / `firebase_create_android_app` / `firebase_get_android_config` / `firebase_create_ios_app` |
72
72
  | AdMob | 7 | `admob_list_apps` / `admob_create_ad_unit` / `admob_get_today_earnings` / `admob_get_report` |
73
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` |
74
+ | Jenkins (크리덴셜 + 잡) | 10 | `jenkins_create_credential` / `jenkins_upload_keystore` / `jenkins_create_job` / `jenkins_update_job` |
75
75
  | GA4 | 6 | `ga4_create_property` / `ga4_create_data_stream` / `ga4_run_report` |
76
76
  | Search Console | 6 | `gsc_inspect_url` / `gsc_search_analytics` / `gsc_submit_sitemap` |
77
77
  | Google Ads | 6 | `googleads_list_campaigns` / `googleads_get_uac_report` / `googleads_get_campaign_report` |
@@ -1,3 +1,12 @@
1
+ /**
2
+ * OAuth client id/secret 해석: env 오버라이드 → 웹 콘솔 원격 조회.
3
+ * (디스크 캐시(credentials.json) 우선 순위는 호출자 — google-auth.ts
4
+ * ensureFreshAccessToken — 가 처리하며, 원격 조회 성공 시 디스크에 저장한다.)
5
+ *
6
+ * 모든 실패는 message 에 'mcp-auth-config' 를 포함해 던진다 —
7
+ * errors.ts classifyError 가 이 마커로 CONFIG_FETCH_FAILED 로 분류해
8
+ * "구글 연결 실패" 같은 오진 대신 정확한 원인/해법을 안내한다.
9
+ */
1
10
  export declare function getMcpOAuthClient(): Promise<{
2
11
  clientId: string;
3
12
  clientSecret: string;
@@ -1,5 +1,14 @@
1
1
  const WEB_BASE = process.env.MIMI_SEED_WEB_BASE ?? 'https://mimi-seed.pryzm.gg';
2
2
  let _cached = null;
3
+ /**
4
+ * OAuth client id/secret 해석: env 오버라이드 → 웹 콘솔 원격 조회.
5
+ * (디스크 캐시(credentials.json) 우선 순위는 호출자 — google-auth.ts
6
+ * ensureFreshAccessToken — 가 처리하며, 원격 조회 성공 시 디스크에 저장한다.)
7
+ *
8
+ * 모든 실패는 message 에 'mcp-auth-config' 를 포함해 던진다 —
9
+ * errors.ts classifyError 가 이 마커로 CONFIG_FETCH_FAILED 로 분류해
10
+ * "구글 연결 실패" 같은 오진 대신 정확한 원인/해법을 안내한다.
11
+ */
3
12
  export async function getMcpOAuthClient() {
4
13
  const id = process.env.MIMI_SEED_GOOGLE_CLIENT_ID ??
5
14
  process.env.PRESEED_GOOGLE_CLIENT_ID;
@@ -9,9 +18,32 @@ export async function getMcpOAuthClient() {
9
18
  return { clientId: id, clientSecret: secret };
10
19
  if (_cached)
11
20
  return _cached;
12
- const res = await fetch(`${WEB_BASE}/api/mcp-auth-config`);
21
+ let res;
22
+ try {
23
+ res = await fetch(`${WEB_BASE}/api/mcp-auth-config`, {
24
+ signal: AbortSignal.timeout(10_000),
25
+ });
26
+ }
27
+ catch (e) {
28
+ const detail = e instanceof Error ? e.message : String(e);
29
+ throw new Error(`mcp-auth-config fetch failed (${WEB_BASE} 접속 불가: ${detail})`);
30
+ }
13
31
  if (!res.ok)
14
32
  throw new Error(`mcp-auth-config fetch failed (${res.status})`);
15
- _cached = (await res.json());
33
+ // body 파싱/검증 실패도 반드시 마커를 달아야 한다 — captive portal 이 200 + HTML 을
34
+ // 돌려주는 첫 설치 환경에서 raw SyntaxError 가 새면 "재로그인하세요" 로 오진된다.
35
+ let data;
36
+ try {
37
+ data = (await res.json());
38
+ }
39
+ catch (e) {
40
+ const detail = e instanceof Error ? e.message : String(e);
41
+ throw new Error(`mcp-auth-config fetch failed (응답이 JSON 이 아님: ${detail})`);
42
+ }
43
+ // 빈 값 200 응답(서버 env 미설정)을 캐싱하면 프로세스 수명 내내 invalid_client 로 오진된다.
44
+ if (!data || typeof data !== 'object' || !data.clientId || !data.clientSecret) {
45
+ throw new Error('mcp-auth-config fetch failed (서버 응답에 clientId/clientSecret 비어 있음)');
46
+ }
47
+ _cached = { clientId: data.clientId, clientSecret: data.clientSecret };
16
48
  return _cached;
17
49
  }
@@ -1,4 +1,4 @@
1
- export type AuthErrorCode = 'UNAUTHENTICATED' | 'NO_REFRESH_TOKEN' | 'INVALID_GRANT' | 'RAPT_REQUIRED' | 'INVALID_CLIENT' | 'UNAUTHORIZED_CLIENT' | 'REFRESH_NETWORK_ERROR' | 'REFRESH_UNKNOWN' | 'INSUFFICIENT_SCOPE' | 'CALLBACK_PORT_IN_USE' | 'CALLBACK_TIMEOUT' | 'BROWSER_OPEN_FAILED' | 'USER_DENIED' | 'CODE_EXCHANGE_FAILED' | 'TOKEN_RESPONSE_INVALID';
1
+ export type AuthErrorCode = 'UNAUTHENTICATED' | 'NO_REFRESH_TOKEN' | 'INVALID_GRANT' | 'RAPT_REQUIRED' | 'INVALID_CLIENT' | 'UNAUTHORIZED_CLIENT' | 'REFRESH_NETWORK_ERROR' | 'CONFIG_FETCH_FAILED' | 'REFRESH_UNKNOWN' | 'INSUFFICIENT_SCOPE' | 'CALLBACK_PORT_IN_USE' | 'CALLBACK_TIMEOUT' | 'BROWSER_OPEN_FAILED' | 'USER_DENIED' | 'CODE_EXCHANGE_FAILED' | 'TOKEN_RESPONSE_INVALID';
2
2
  export interface AuthErrorPayload {
3
3
  code: AuthErrorCode;
4
4
  message: string;
@@ -63,13 +63,28 @@ export function classifyError(e, ctx) {
63
63
  if (oauthCode === 'access_denied') {
64
64
  return {
65
65
  code: 'USER_DENIED',
66
- message: '브라우저에서 Google 동의를 거부했습니다.',
67
- hint: '다시 시도하고 모든 권한에 동의해주세요.',
66
+ message: 'Google 동의가 거부되었습니다 (access_denied).',
67
+ hint: '직접 거부하지 않았다면: OAuth 앱은 Google 미검증(테스트) 상태라 등록된 테스트 사용자만 로그인할 수 있습니다. ' +
68
+ '운영자에게 Google Cloud Console → OAuth 동의 화면 → 테스트 사용자에 이 계정 추가를 요청한 뒤 재시도하세요. ' +
69
+ '직접 거부했다면 다시 시도해 모든 권한에 동의해주세요.',
68
70
  retriable: true,
69
71
  needsReauth: true,
70
72
  cause: raw,
71
73
  };
72
74
  }
75
+ // OAuth client 설정 조회 실패 — 구글이 아니라 mimi-seed 웹 콘솔 쪽 문제.
76
+ // 네트워크 분류보다 먼저 검사해야 "oauth2.googleapis.com 연결 실패" 오진을 막는다.
77
+ if (/mcp-auth-config/i.test(raw)) {
78
+ return {
79
+ code: 'CONFIG_FETCH_FAILED',
80
+ message: 'Mimi Seed 서버에서 OAuth 클라이언트 설정을 받지 못했습니다.',
81
+ hint: 'mimi-seed.pryzm.gg 접속 가능 여부를 확인하거나, ' +
82
+ '환경변수 MIMI_SEED_GOOGLE_CLIENT_ID / MIMI_SEED_GOOGLE_CLIENT_SECRET 로 자체 OAuth 클라이언트를 지정하세요.',
83
+ retriable: true,
84
+ needsReauth: false,
85
+ cause: raw,
86
+ };
87
+ }
73
88
  // 네트워크 / 시스템 레벨
74
89
  if (isNetworkError(e, raw)) {
75
90
  return {
@@ -316,11 +316,29 @@ export async function ensureFreshAccessToken(marginMs = 300_000) {
316
316
  },
317
317
  };
318
318
  }
319
- // refresh 시도 — credentials.json 우선, 없으면 원격에서 클라이언트 조회
319
+ // refresh 시도 — credentials.json(디스크) 우선. 디스크에 있으면 원격 조회 자체를 안 한다 —
320
+ // 매시간 refresh 가 웹 콘솔 생존에 의존하면 콘솔 장애가 모든 로컬 도구 호출을 죽인다.
321
+ // 없을 때만 env → 원격(getMcpOAuthClient) 순으로 받고, 성공 시 디스크에 저장해
322
+ // 원격 의존을 최초 1회로 끝낸다. 조회 실패는 raw throw 가 아니라 분류된 에러로 반환.
323
+ let clientId;
324
+ let clientSecret;
320
325
  const stored = getStoredCredentials();
321
- const { clientId: defaultId, clientSecret: defaultSecret } = await getMcpOAuthClient();
322
- const clientId = stored?.clientId ?? defaultId;
323
- const clientSecret = stored?.clientSecret ?? defaultSecret;
326
+ if (stored?.clientId && stored?.clientSecret) {
327
+ ({ clientId, clientSecret } = stored);
328
+ }
329
+ else {
330
+ try {
331
+ ({ clientId, clientSecret } = await getMcpOAuthClient());
332
+ saveCredentials(clientId, clientSecret);
333
+ }
334
+ catch (e) {
335
+ return {
336
+ status: 'expired_refresh_failed',
337
+ tokens,
338
+ error: classifyError(e, { phase: 'refresh' }),
339
+ };
340
+ }
341
+ }
324
342
  const client = createOAuth2Client(clientId, clientSecret);
325
343
  client.setCredentials({ refresh_token: tokens.refresh_token });
326
344
  try {
package/dist/helpers.js CHANGED
@@ -4,12 +4,12 @@ import { getAppStoreCredentials } from './appstore/auth.js';
4
4
  export { ensureFreshAccessToken };
5
5
  const REAUTH_CMD = ' npx -y @yoonion/mimi-seed-mcp mimi-seed-auth';
6
6
  function formatAuthError(p) {
7
+ // 재로그인 안내는 needsReauth 인 경우에만 — CONFIG_FETCH_FAILED 처럼 재로그인이
8
+ // 해법이 아닌 에러에 무조건 붙이면 같은 실패를 반복하게 만든다.
7
9
  return [
8
10
  `❌ [${p.code}] ${p.message}`,
9
11
  p.hint ? `→ ${p.hint}` : '',
10
- '',
11
- '터미널에서 재로그인:',
12
- REAUTH_CMD,
12
+ ...(p.needsReauth ? ['', '터미널에서 재로그인:', REAUTH_CMD] : []),
13
13
  ]
14
14
  .filter((l) => l !== '')
15
15
  .join('\n');
package/dist/index.js CHANGED
@@ -1,52 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import { readFileSync } from 'node:fs';
3
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
4
3
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
5
- import { registerFirebaseTools } from './registers/firebase.js';
6
- import { registerAdmobTools } from './registers/admob.js';
7
- import { registerPlaystoreTools } from './registers/playstore.js';
8
- import { registerIamTools } from './registers/iam.js';
9
- import { registerAppstoreTools } from './registers/appstore.js';
10
- import { registerChecksTools } from './registers/checks.js';
11
- import { registerAiTools } from './registers/ai.js';
12
- import { registerBigqueryTools } from './registers/bigquery.js';
13
- import { registerAuthTools } from './registers/auth.js';
14
- import { registerCiTools } from './registers/ci.js';
15
- import { registerInstagramTools } from './registers/instagram.js';
16
- import { registerFacebookTools } from './registers/facebook.js';
17
- import { registerGoogleAdsTools } from './registers/googleads.js';
18
- import { registerGscTools } from './registers/gsc.js';
19
- import { registerGa4Tools } from './registers/ga4.js';
20
- import { registerJenkinsTools } from './registers/jenkins.js';
21
- import { registerAndroidTools } from './registers/android.js';
22
- import { registerPrompts } from './prompts.js';
23
- import { registerResources } from './resources.js';
4
+ import { buildServer } from './server.js';
24
5
  // dist/index.js 기준 ../package.json — npm 패키지 루트의 버전을 단일 출처로 사용.
25
6
  // 하드코딩하면 publish 때마다 serverInfo.version 이 드리프트하므로 런타임에 읽는다.
26
7
  const { version } = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
27
- const server = new McpServer({
28
- name: 'mimi-seed',
29
- version,
30
- });
31
- registerFirebaseTools(server);
32
- registerAdmobTools(server);
33
- registerPlaystoreTools(server);
34
- registerIamTools(server);
35
- registerAppstoreTools(server);
36
- registerChecksTools(server);
37
- registerAiTools(server);
38
- registerBigqueryTools(server);
39
- registerAuthTools(server);
40
- registerCiTools(server);
41
- registerInstagramTools(server);
42
- registerFacebookTools(server);
43
- registerGoogleAdsTools(server);
44
- registerGscTools(server);
45
- registerGa4Tools(server);
46
- registerJenkinsTools(server);
47
- registerAndroidTools(server);
48
- registerPrompts(server);
49
- registerResources(server);
50
8
  // `npx -y @yoonion/mimi-seed-mcp <subcommand>` 처리.
51
9
  // npx는 스코프 패키지의 basename(`mimi-seed-mcp`)을 매치해 이 bin을 실행하므로,
52
10
  // 추가 인자(`mimi-seed-auth` 등)는 여기 argv로 흘러들어온다. 이전엔 MCP 서버가
@@ -80,6 +38,7 @@ async function main() {
80
38
  ].join('\n'));
81
39
  process.exit(2);
82
40
  }
41
+ const server = buildServer(version);
83
42
  const transport = new StdioServerTransport();
84
43
  await server.connect(transport);
85
44
  }
@@ -1,4 +1,6 @@
1
+ import { readFileSync } from 'node:fs';
1
2
  import { getMcpOAuthClient } from '../auth/constants.js';
3
+ import { classifyError } from '../auth/errors.js';
2
4
  import { startAuth, ensureFreshAccessToken, getTokensLastRefreshMs } from '../auth/google-auth.js';
3
5
  import { listRegisteredServiceAccounts } from '../auth/playstore-auth.js';
4
6
  import { getAppStoreCredentials } from '../appstore/auth.js';
@@ -43,8 +45,11 @@ const MANIFEST_FIX = {
43
45
  ? `setup_playstore_connection(packageName="${svc.packageName}")`
44
46
  : 'setup_playstore_connection(packageName=...)',
45
47
  appstore: () => 'npx -y @yoonion/mimi-seed-mcp mimi-seed-appstore-auth',
46
- jenkins: () => 'claude mcp add virgm-jenkins -s user (개인 자격증명 — .mcp.json 금지)',
48
+ jenkins: () => 'claude mcp add <your-jenkins-mcp> -s user (개인 자격증명 — .mcp.json 금지)',
47
49
  };
50
+ // 두 MCP 가 모두 'mimi-seed' 로 등록되는 환경에서 에이전트가 프로그램적으로
51
+ // 어느 서버인지 판별할 수 있도록 status 첫 줄에 자기소개를 넣는다.
52
+ const { version: PKG_VERSION } = JSON.parse(readFileSync(new URL('../../package.json', import.meta.url), 'utf8'));
48
53
  /** 서비스별 식별자를 한 줄 detail 로 (예: "ads-coffee / analytics_530080532"). */
49
54
  function manifestServiceDetail(id, svc) {
50
55
  const parts = [];
@@ -91,7 +96,10 @@ export function registerAuthTools(server) {
91
96
  '설정 상태를 한 번에 스캔해 ✅ / ❌ 트래픽 라이트 리포트와 번호 매긴 다음 단계를 반환합니다.',
92
97
  '미설정 서비스마다 어떤 도구를 호출하면 되는지 구체적으로 알려줍니다.',
93
98
  ].join(' '), {}, async () => {
94
- const lines = ['🌱 Mimi Seed 연결 상태', ''];
99
+ const lines = [
100
+ `🌱 Mimi Seed 연결 상태 — local-stdio (@yoonion/mimi-seed-mcp v${PKG_VERSION})`,
101
+ '',
102
+ ];
95
103
  // 1. Google OAuth
96
104
  const oauthResult = await ensureFreshAccessToken();
97
105
  if (oauthResult.status === 'fresh' || oauthResult.status === 'refreshed') {
@@ -121,7 +129,7 @@ export function registerAuthTools(server) {
121
129
  lines.push(`✅ App Store Connect — 연결됨 (keyId: ${asc.keyId})`);
122
130
  }
123
131
  else {
124
- lines.push('❌ App Store Connect — 미설정 → npx @yoonion/mimi-seed-mcp mimi-seed-appstore-auth');
132
+ lines.push('❌ App Store Connect — 미설정 → npx -y @yoonion/mimi-seed-mcp mimi-seed-appstore-auth');
125
133
  }
126
134
  // 4. Jenkins
127
135
  const jenkins = loadJenkinsConfig();
@@ -173,7 +181,7 @@ export function registerAuthTools(server) {
173
181
  lines.push('⚠️ BigQuery — OAuth fallback (Workspace 재인증 정책 시 끊길 수 있음 → 서비스 계정 권장: mimi-seed-bigquery-auth)');
174
182
  }
175
183
  else {
176
- lines.push('❌ BigQuery — 미설정 → npx @yoonion/mimi-seed-mcp mimi-seed-bigquery-auth (선택)');
184
+ lines.push('❌ BigQuery — 미설정 → npx -y @yoonion/mimi-seed-mcp mimi-seed-bigquery-auth (선택)');
177
185
  }
178
186
  // 다음 단계 안내
179
187
  const missing = [];
@@ -184,7 +192,7 @@ export function registerAuthTools(server) {
184
192
  missing.push(' 2. setup_playstore_connection(packageName=..., projectId=...) (Play Store 배포 필수)');
185
193
  }
186
194
  if (!asc) {
187
- missing.push(' 3. npx @yoonion/mimi-seed-mcp mimi-seed-appstore-auth (App Store 배포 필수)');
195
+ missing.push(' 3. npx -y @yoonion/mimi-seed-mcp mimi-seed-appstore-auth (App Store 배포 필수)');
188
196
  }
189
197
  if (missing.length > 0) {
190
198
  lines.push('', '── 다음 단계 (필수) ─────────────────────────────', ...missing);
@@ -230,7 +238,21 @@ export function registerAuthTools(server) {
230
238
  '이후 playstore_*, firebase_*, admob_* 등 다른 MCP 도구 바로 호출 가능.',
231
239
  '토큰 만료(invalid_rapt) / 재인증 필요 시 사용. 10분 내 완료해야 함.',
232
240
  ].join(' '), {}, async () => {
233
- const { clientId, clientSecret } = await getMcpOAuthClient();
241
+ // 설정 조회 실패를 분류된 안내로 raw throw 는 MCP 클라이언트에 마커 문자열만 노출된다.
242
+ let clientId;
243
+ let clientSecret;
244
+ try {
245
+ ({ clientId, clientSecret } = await getMcpOAuthClient());
246
+ }
247
+ catch (e) {
248
+ const p = classifyError(e, { phase: 'login' });
249
+ return {
250
+ content: [{
251
+ type: 'text',
252
+ text: `❌ [${p.code}] ${p.message}${p.hint ? `\n→ ${p.hint}` : ''}`,
253
+ }],
254
+ };
255
+ }
234
256
  const { url, wait } = startAuth(clientId, clientSecret);
235
257
  // fire-and-forget — 토큰은 콜백 서버가 자동 저장
236
258
  wait.then(() => { }, (err) => { console.error('[mimi-seed auth]', err.message); });
@@ -290,8 +312,11 @@ export function registerAuthTools(server) {
290
312
  ` 코드: ${r.error.code}\n` +
291
313
  ` ${r.error.message}\n` +
292
314
  (r.error.hint ? ` → ${r.error.hint}\n` : '') +
293
- `${refreshLine}\n` +
294
- '\n터미널에서 재로그인:\n npx -y @yoonion/mimi-seed-mcp mimi-seed-auth',
315
+ `${refreshLine}` +
316
+ // 재로그인 안내는 그것이 실제 해법일 때만 (네트워크/설정 조회 실패엔 무의미)
317
+ (r.error.needsReauth
318
+ ? '\n\n터미널에서 재로그인:\n npx -y @yoonion/mimi-seed-mcp mimi-seed-auth'
319
+ : ''),
295
320
  }],
296
321
  };
297
322
  }
package/dist/resources.js CHANGED
@@ -25,7 +25,7 @@ export function registerResources(server) {
25
25
  '# Mimi Seed — 앱 출시·운영 Agent',
26
26
  '',
27
27
  '당신은 Mimi Seed MCP를 통해 인디 개발자의 앱 출시와 운영을 돕는 에이전트입니다.',
28
- 'Google Play · App Store · Firebase · AdMob · CI/CD · BigQuery를 직접 제어하는 110+ 도구를 사용할 수 있습니다.',
28
+ 'Google Play · App Store · Firebase · AdMob · CI/CD · BigQuery를 직접 제어하는 150+ 도구를 사용할 수 있습니다.',
29
29
  '',
30
30
  '## 출시 요청 처리 순서',
31
31
  '',
@@ -0,0 +1,7 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ /**
3
+ * 서버 조립 단일 지점 — stdio 엔트리(index.ts)와 tool-manifest 스모크 테스트
4
+ * (src/__tests__/tool-manifest.test.ts)가 공유한다. 새 register 모듈은 반드시
5
+ * 여기(index.ts 가 아니라)에 추가해야 테스트가 tool-manifest.json 과의 드리프트를 잡는다.
6
+ */
7
+ export declare function buildServer(version: string): McpServer;
package/dist/server.js ADDED
@@ -0,0 +1,54 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { registerFirebaseTools } from './registers/firebase.js';
3
+ import { registerAdmobTools } from './registers/admob.js';
4
+ import { registerPlaystoreTools } from './registers/playstore.js';
5
+ import { registerIamTools } from './registers/iam.js';
6
+ import { registerAppstoreTools } from './registers/appstore.js';
7
+ import { registerChecksTools } from './registers/checks.js';
8
+ import { registerAiTools } from './registers/ai.js';
9
+ import { registerBigqueryTools } from './registers/bigquery.js';
10
+ import { registerAuthTools } from './registers/auth.js';
11
+ import { registerCiTools } from './registers/ci.js';
12
+ import { registerInstagramTools } from './registers/instagram.js';
13
+ import { registerFacebookTools } from './registers/facebook.js';
14
+ import { registerGoogleAdsTools } from './registers/googleads.js';
15
+ import { registerGscTools } from './registers/gsc.js';
16
+ import { registerGa4Tools } from './registers/ga4.js';
17
+ import { registerJenkinsTools } from './registers/jenkins.js';
18
+ import { registerAndroidTools } from './registers/android.js';
19
+ import { registerPrompts } from './prompts.js';
20
+ import { registerResources } from './resources.js';
21
+ /**
22
+ * 서버 조립 단일 지점 — stdio 엔트리(index.ts)와 tool-manifest 스모크 테스트
23
+ * (src/__tests__/tool-manifest.test.ts)가 공유한다. 새 register 모듈은 반드시
24
+ * 여기(index.ts 가 아니라)에 추가해야 테스트가 tool-manifest.json 과의 드리프트를 잡는다.
25
+ */
26
+ export function buildServer(version) {
27
+ // serverInfo.name 은 'mimi-seed-local' — 웹 콘솔의 Remote HTTP MCP(mimi-seed-web)와
28
+ // 핸드셰이크 수준에서 구분한다. 클라이언트 표시명/도구 네임스페이스(mcp__mimi-seed__*)는
29
+ // 등록 키(.mcp.json / claude mcp add 의 이름)에서 오므로 이 값 변경은 호환성에 영향 없음.
30
+ const server = new McpServer({
31
+ name: 'mimi-seed-local',
32
+ version,
33
+ });
34
+ registerFirebaseTools(server);
35
+ registerAdmobTools(server);
36
+ registerPlaystoreTools(server);
37
+ registerIamTools(server);
38
+ registerAppstoreTools(server);
39
+ registerChecksTools(server);
40
+ registerAiTools(server);
41
+ registerBigqueryTools(server);
42
+ registerAuthTools(server);
43
+ registerCiTools(server);
44
+ registerInstagramTools(server);
45
+ registerFacebookTools(server);
46
+ registerGoogleAdsTools(server);
47
+ registerGscTools(server);
48
+ registerGa4Tools(server);
49
+ registerJenkinsTools(server);
50
+ registerAndroidTools(server);
51
+ registerPrompts(server);
52
+ registerResources(server);
53
+ return server;
54
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yoonion/mimi-seed-mcp",
3
- "version": "0.6.1",
3
+ "version": "0.6.3",
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": {