@yoonion/mimi-seed-mcp 0.3.17 → 0.3.19

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.
@@ -0,0 +1,122 @@
1
+ import { z } from 'zod';
2
+ import * as firebase from '../firebase/tools.js';
3
+ import { requireAuth } from '../helpers.js';
4
+ export function registerFirebaseTools(server) {
5
+ server.tool('firebase_list_projects', '내 Firebase 프로젝트 목록 조회', {}, async () => {
6
+ const auth = requireAuth();
7
+ const projects = await firebase.listProjects(auth);
8
+ return { content: [{ type: 'text', text: JSON.stringify(projects, null, 2) }] };
9
+ });
10
+ server.tool('firebase_get_project', 'Firebase 프로젝트 상세 정보 조회', { projectId: z.string().describe('Firebase 프로젝트 ID') }, async ({ projectId }) => {
11
+ const auth = requireAuth();
12
+ const project = await firebase.getProject(auth, projectId);
13
+ return { content: [{ type: 'text', text: JSON.stringify(project, null, 2) }] };
14
+ });
15
+ server.tool('firebase_list_android_apps', 'Firebase 프로젝트의 Android 앱 목록', { projectId: z.string().describe('Firebase 프로젝트 ID') }, async ({ projectId }) => {
16
+ const auth = requireAuth();
17
+ const apps = await firebase.listAndroidApps(auth, projectId);
18
+ return { content: [{ type: 'text', text: JSON.stringify(apps, null, 2) }] };
19
+ });
20
+ server.tool('firebase_create_android_app', 'Firebase에 새 Android 앱 등록', {
21
+ projectId: z.string().describe('Firebase 프로젝트 ID'),
22
+ packageName: z.string().describe('Android 패키지명 (예: com.example.myapp)'),
23
+ displayName: z.string().describe('앱 표시 이름'),
24
+ }, async ({ projectId, packageName, displayName }) => {
25
+ const auth = requireAuth();
26
+ const result = await firebase.createAndroidApp(auth, projectId, packageName, displayName);
27
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
28
+ });
29
+ server.tool('firebase_get_android_config', 'google-services.json 다운로드', {
30
+ projectId: z.string().describe('Firebase 프로젝트 ID'),
31
+ appId: z.string().describe('Firebase 앱 ID'),
32
+ }, async ({ projectId, appId }) => {
33
+ const auth = requireAuth();
34
+ const config = await firebase.getAndroidConfig(auth, projectId, appId);
35
+ return { content: [{ type: 'text', text: JSON.stringify(config, null, 2) }] };
36
+ });
37
+ server.tool('firebase_delete_android_app', 'Firebase Android 앱 삭제', {
38
+ projectId: z.string().describe('Firebase 프로젝트 ID'),
39
+ appId: z.string().describe('삭제할 Firebase 앱 ID'),
40
+ }, async ({ projectId, appId }) => {
41
+ const auth = requireAuth();
42
+ const result = await firebase.deleteAndroidApp(auth, projectId, appId);
43
+ return { content: [{ type: 'text', text: `삭제 완료: ${JSON.stringify(result)}` }] };
44
+ });
45
+ server.tool('firebase_list_ios_apps', 'Firebase 프로젝트의 iOS 앱 목록', { projectId: z.string().describe('Firebase 프로젝트 ID') }, async ({ projectId }) => {
46
+ const auth = requireAuth();
47
+ const apps = await firebase.listIosApps(auth, projectId);
48
+ return { content: [{ type: 'text', text: JSON.stringify(apps, null, 2) }] };
49
+ });
50
+ server.tool('firebase_create_ios_app', 'Firebase에 새 iOS 앱 등록', {
51
+ projectId: z.string().describe('Firebase 프로젝트 ID'),
52
+ bundleId: z.string().describe('iOS Bundle ID (예: com.example.myapp)'),
53
+ displayName: z.string().describe('앱 표시 이름'),
54
+ }, async ({ projectId, bundleId, displayName }) => {
55
+ const auth = requireAuth();
56
+ const result = await firebase.createIosApp(auth, projectId, bundleId, displayName);
57
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
58
+ });
59
+ server.tool('firebase_get_ios_config', 'GoogleService-Info.plist 다운로드', {
60
+ projectId: z.string().describe('Firebase 프로젝트 ID'),
61
+ appId: z.string().describe('Firebase 앱 ID'),
62
+ }, async ({ projectId, appId }) => {
63
+ const auth = requireAuth();
64
+ const config = await firebase.getIosConfig(auth, projectId, appId);
65
+ return { content: [{ type: 'text', text: JSON.stringify(config, null, 2) }] };
66
+ });
67
+ server.tool('firebase_delete_ios_app', 'Firebase iOS 앱 삭제', {
68
+ projectId: z.string().describe('Firebase 프로젝트 ID'),
69
+ appId: z.string().describe('삭제할 Firebase 앱 ID'),
70
+ }, async ({ projectId, appId }) => {
71
+ const auth = requireAuth();
72
+ const result = await firebase.deleteIosApp(auth, projectId, appId);
73
+ return { content: [{ type: 'text', text: `삭제 완료: ${JSON.stringify(result)}` }] };
74
+ });
75
+ server.tool('firebase_list_web_apps', 'Firebase 프로젝트의 Web 앱 목록', { projectId: z.string().describe('Firebase 프로젝트 ID') }, async ({ projectId }) => {
76
+ const auth = requireAuth();
77
+ const apps = await firebase.listWebApps(auth, projectId);
78
+ return { content: [{ type: 'text', text: JSON.stringify(apps, null, 2) }] };
79
+ });
80
+ server.tool('firebase_create_web_app', 'Firebase에 새 Web 앱 등록', {
81
+ projectId: z.string().describe('Firebase 프로젝트 ID'),
82
+ displayName: z.string().describe('앱 표시 이름'),
83
+ }, async ({ projectId, displayName }) => {
84
+ const auth = requireAuth();
85
+ const result = await firebase.createWebApp(auth, projectId, displayName);
86
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
87
+ });
88
+ server.tool('firebase_get_web_config', 'Firebase Web 설정 (firebaseConfig 객체) 조회', {
89
+ projectId: z.string().describe('Firebase 프로젝트 ID'),
90
+ appId: z.string().describe('Firebase 앱 ID'),
91
+ }, async ({ projectId, appId }) => {
92
+ const auth = requireAuth();
93
+ const config = await firebase.getWebConfig(auth, projectId, appId);
94
+ return { content: [{ type: 'text', text: JSON.stringify(config, null, 2) }] };
95
+ });
96
+ server.tool('firebase_delete_web_app', 'Firebase Web 앱 삭제', {
97
+ projectId: z.string().describe('Firebase 프로젝트 ID'),
98
+ appId: z.string().describe('삭제할 Firebase 앱 ID'),
99
+ }, async ({ projectId, appId }) => {
100
+ const auth = requireAuth();
101
+ const result = await firebase.deleteWebApp(auth, projectId, appId);
102
+ return { content: [{ type: 'text', text: `삭제 완료: ${JSON.stringify(result)}` }] };
103
+ });
104
+ server.tool('firebase_enable_service', 'GCP 서비스 활성화 (예: firestore.googleapis.com)', {
105
+ projectId: z.string().describe('프로젝트 ID'),
106
+ serviceId: z.string().describe('서비스 ID (예: firestore.googleapis.com)'),
107
+ }, async ({ projectId, serviceId }) => {
108
+ const auth = requireAuth();
109
+ const result = await firebase.enableService(auth, projectId, serviceId);
110
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
111
+ });
112
+ server.tool('firebase_enable_common_services', 'Firebase 기본 서비스 일괄 활성화 (Firestore, Auth, Storage, FCM 등)', { projectId: z.string().describe('프로젝트 ID') }, async ({ projectId }) => {
113
+ const auth = requireAuth();
114
+ const results = await firebase.enableCommonServices(auth, projectId);
115
+ return { content: [{ type: 'text', text: JSON.stringify(results, null, 2) }] };
116
+ });
117
+ server.tool('firebase_list_enabled_services', '프로젝트에서 활성화된 GCP 서비스 목록', { projectId: z.string().describe('프로젝트 ID') }, async ({ projectId }) => {
118
+ const auth = requireAuth();
119
+ const services = await firebase.listEnabledServices(auth, projectId);
120
+ return { content: [{ type: 'text', text: JSON.stringify(services, null, 2) }] };
121
+ });
122
+ }
@@ -0,0 +1,2 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerIamTools(server: McpServer): void;
@@ -0,0 +1,105 @@
1
+ import { z } from 'zod';
2
+ import * as iam from '../iam/tools.js';
3
+ import { requireAuth } from '../helpers.js';
4
+ export function registerIamTools(server) {
5
+ server.tool('iam_list_service_accounts', '주어진 projectId의 서비스 계정 목록. 이메일 / displayName / disabled 상태 반환.', {
6
+ projectId: z.string().describe('Google Cloud 프로젝트 ID'),
7
+ }, async ({ projectId }) => {
8
+ const auth = requireAuth();
9
+ const accounts = await iam.listServiceAccounts(auth, projectId);
10
+ return { content: [{ type: 'text', text: JSON.stringify(accounts, null, 2) }] };
11
+ });
12
+ server.tool('iam_create_service_account', '새 서비스 계정 생성. accountId는 이메일의 로컬 파트 (예: "onesub-play-verifier" → onesub-play-verifier@<project>.iam.gserviceaccount.com).', {
13
+ projectId: z.string().describe('Google Cloud 프로젝트 ID'),
14
+ accountId: z
15
+ .string()
16
+ .regex(/^[a-z][a-z0-9-]{4,28}[a-z0-9]$/, 'lowercase letters, digits, hyphens; 6-30 chars')
17
+ .describe('서비스 계정 ID (이메일 로컬 파트)'),
18
+ displayName: z.string().describe('사람이 읽을 표시 이름 (예: "onesub Play verifier")'),
19
+ }, async ({ projectId, accountId, displayName }) => {
20
+ const auth = requireAuth();
21
+ const account = await iam.createServiceAccount(auth, projectId, accountId, displayName);
22
+ return {
23
+ content: [
24
+ {
25
+ type: 'text',
26
+ text: [
27
+ '✓ 서비스 계정 생성 완료',
28
+ '',
29
+ `**email**: \`${account.email}\``,
30
+ `**displayName**: ${account.displayName}`,
31
+ `**uniqueId**: \`${account.uniqueId}\``,
32
+ '',
33
+ '다음 단계:',
34
+ `1. \`iam_create_key("${account.email}")\` — JSON 키 발급`,
35
+ `2. \`playstore_verify_service_account\` 로 Play Console 권한까지 확인 (Play Console에서 수동으로 이메일 초대 + 'View financial data' 권한 부여는 별도)`,
36
+ ].join('\n'),
37
+ },
38
+ ],
39
+ };
40
+ });
41
+ server.tool('iam_list_keys', '주어진 서비스 계정의 기존 키 목록. keyId / keyType / 만료시간 반환. 회수할 키 찾을 때 사용.', {
42
+ serviceAccount: z.string().describe('서비스 계정 이메일'),
43
+ }, async ({ serviceAccount }) => {
44
+ const auth = requireAuth();
45
+ const keys = await iam.listServiceAccountKeys(auth, serviceAccount);
46
+ return { content: [{ type: 'text', text: JSON.stringify(keys, null, 2) }] };
47
+ });
48
+ server.tool('iam_create_key', [
49
+ '주어진 서비스 계정의 새 JSON 키를 발급. 응답에 전체 JSON 포함 — 그대로 onesub의 GOOGLE_SERVICE_ACCOUNT_KEY 환경변수로 쓸 수 있음.',
50
+ '주의: 반환된 JSON은 영구 자격증명이므로 안전하게 보관. 한 서비스 계정당 키 최대 10개 (기존 키 회수 후 발급 필요하면 iam_list_keys로 먼저 확인).',
51
+ ].join(' '), {
52
+ serviceAccount: z.string().describe('서비스 계정 이메일'),
53
+ }, async ({ serviceAccount }) => {
54
+ const auth = requireAuth();
55
+ const key = await iam.createServiceAccountKey(auth, serviceAccount);
56
+ return {
57
+ content: [
58
+ {
59
+ type: 'text',
60
+ text: [
61
+ '✓ 새 키 발급 완료 — 아래 JSON을 안전하게 보관하세요. **다시 볼 수 없습니다.**',
62
+ '',
63
+ `**keyId**: \`${key.keyId}\``,
64
+ `**clientEmail**: \`${key.clientEmail}\``,
65
+ `**projectId**: \`${key.projectId}\``,
66
+ '',
67
+ '## Service account JSON',
68
+ '```json',
69
+ key.json,
70
+ '```',
71
+ '',
72
+ 'onesub 서버 `GOOGLE_SERVICE_ACCOUNT_KEY` env에 한 줄로 넣을 때:',
73
+ '```bash',
74
+ "cat service-account.json | tr -d '\\n' | jq -c .",
75
+ '```',
76
+ ].join('\n'),
77
+ },
78
+ ],
79
+ };
80
+ });
81
+ server.tool('iam_add_iam_policy_binding', [
82
+ '프로젝트 IAM 정책에 (member → role) 바인딩 추가. 이미 같은 조합이 있으면 no-op.',
83
+ 'member 형식: `serviceAccount:<email>` / `user:<email>` / `group:<email>`.',
84
+ '주의: 이건 Google Cloud IAM 역할입니다. Play Console의 "View financial data" 권한은 별도 — Play Console → Users and permissions에서 부여.',
85
+ ].join(' '), {
86
+ projectId: z.string().describe('Google Cloud 프로젝트 ID'),
87
+ member: z
88
+ .string()
89
+ .describe('권한 받을 주체 (예: serviceAccount:my-sa@my-project.iam.gserviceaccount.com)'),
90
+ role: z.string().describe('IAM 역할 (예: roles/iam.serviceAccountTokenCreator)'),
91
+ }, async ({ projectId, member, role }) => {
92
+ const auth = requireAuth();
93
+ const result = await iam.addProjectIamPolicyBinding(auth, projectId, member, role);
94
+ return {
95
+ content: [
96
+ {
97
+ type: 'text',
98
+ text: result.added
99
+ ? `✓ 바인딩 추가: \`${member}\` → \`${role}\``
100
+ : `• 이미 존재: \`${member}\` → \`${role}\` (no-op)`,
101
+ },
102
+ ],
103
+ };
104
+ });
105
+ }
@@ -0,0 +1,2 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerPlaystoreTools(server: McpServer): void;