@theihtisham/mcp-server-firebase 1.0.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.
Files changed (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +362 -0
  3. package/dist/index.d.ts +3 -0
  4. package/dist/index.js +79 -0
  5. package/dist/services/firebase.d.ts +14 -0
  6. package/dist/services/firebase.js +163 -0
  7. package/dist/tools/auth.d.ts +3 -0
  8. package/dist/tools/auth.js +346 -0
  9. package/dist/tools/firestore.d.ts +3 -0
  10. package/dist/tools/firestore.js +802 -0
  11. package/dist/tools/functions.d.ts +3 -0
  12. package/dist/tools/functions.js +168 -0
  13. package/dist/tools/index.d.ts +10 -0
  14. package/dist/tools/index.js +30 -0
  15. package/dist/tools/messaging.d.ts +3 -0
  16. package/dist/tools/messaging.js +296 -0
  17. package/dist/tools/realtime-db.d.ts +4 -0
  18. package/dist/tools/realtime-db.js +271 -0
  19. package/dist/tools/storage.d.ts +3 -0
  20. package/dist/tools/storage.js +279 -0
  21. package/dist/tools/types.d.ts +11 -0
  22. package/dist/tools/types.js +3 -0
  23. package/dist/utils/cache.d.ts +16 -0
  24. package/dist/utils/cache.js +75 -0
  25. package/dist/utils/errors.d.ts +15 -0
  26. package/dist/utils/errors.js +94 -0
  27. package/dist/utils/index.d.ts +5 -0
  28. package/dist/utils/index.js +37 -0
  29. package/dist/utils/pagination.d.ts +28 -0
  30. package/dist/utils/pagination.js +75 -0
  31. package/dist/utils/validation.d.ts +22 -0
  32. package/dist/utils/validation.js +172 -0
  33. package/package.json +53 -0
  34. package/src/index.ts +94 -0
  35. package/src/services/firebase.ts +140 -0
  36. package/src/tools/auth.ts +375 -0
  37. package/src/tools/firestore.ts +931 -0
  38. package/src/tools/functions.ts +189 -0
  39. package/src/tools/index.ts +24 -0
  40. package/src/tools/messaging.ts +324 -0
  41. package/src/tools/realtime-db.ts +307 -0
  42. package/src/tools/storage.ts +314 -0
  43. package/src/tools/types.ts +10 -0
  44. package/src/utils/cache.ts +82 -0
  45. package/src/utils/errors.ts +110 -0
  46. package/src/utils/index.ts +4 -0
  47. package/src/utils/pagination.ts +105 -0
  48. package/src/utils/validation.ts +212 -0
  49. package/tests/cache.test.ts +139 -0
  50. package/tests/errors.test.ts +132 -0
  51. package/tests/firebase-service.test.ts +46 -0
  52. package/tests/pagination.test.ts +26 -0
  53. package/tests/tools.test.ts +226 -0
  54. package/tests/validation.test.ts +216 -0
  55. package/tsconfig.json +26 -0
  56. package/vitest.config.ts +15 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,362 @@
1
+ # MCP Server Firebase
2
+
3
+ [![npm version](https://img.shields.io/npm/v/mcp-server-firebase.svg)](https://www.npmjs.com/package/mcp-server-firebase)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![Node.js >=18](https://img.shields.io/badge/node-%3E%3D18-brightgreen.svg)](https://nodejs.org/)
6
+ [![TypeScript Strict](https://img.shields.io/badge/typescript-strict-blue.svg)](https://www.typescriptlang.org/)
7
+ [![Vitest](https://img.shields.io/badge/tested_with-vitest-6da13f.svg)](https://vitest.dev/)
8
+
9
+ > **Give AI assistants full Firebase superpowers -- manage Firestore, Auth, Storage, and more through natural language.**
10
+
11
+ An MCP (Model Context Protocol) server that provides AI assistants like Claude with complete access to Firebase services. Query Firestore, manage users, upload files, send notifications, and more -- all through conversational AI.
12
+
13
+ ---
14
+
15
+ ## Features
16
+
17
+ - **37 tools** across 6 Firebase services
18
+ - **Firestore**: Query, CRUD, batch writes, transactions, aggregation, real-time listeners, schema inference
19
+ - **Auth**: Create, read, update, delete users, verify tokens, manage custom claims
20
+ - **Storage**: Upload, download, list, delete files, generate signed URLs
21
+ - **Realtime DB**: Full CRUD with advanced querying (orderBy, filters, limits)
22
+ - **Cloud Functions**: List, trigger, read logs
23
+ - **Messaging (FCM)**: Send notifications, multicast, topic subscriptions
24
+ - **Secure by default**: Input validation, NoSQL injection prevention, path traversal protection
25
+ - **Production-ready**: LRU caching, automatic pagination, connection pooling, structured errors with fix suggestions
26
+ - **Type-safe**: TypeScript strict mode with comprehensive Zod-style validation
27
+
28
+ ---
29
+
30
+ ## Demo Conversation
31
+
32
+ ```
33
+ User: Show me all users who signed up this week
34
+
35
+ AI: I'll query the users collection, filtering by creation date.
36
+
37
+ [calls firestore_query with:
38
+ collection: "users"
39
+ where: [{ field: "createdAt", operator: ">=", value: "2026-04-04" }]
40
+ orderBy: [{ field: "createdAt", direction: "desc" }]
41
+ ]
42
+
43
+ Found 23 users who signed up since April 4th. Here are the most recent:
44
+
45
+ | Name | Email | Joined |
46
+ |---------------|----------------------|---------------|
47
+ | Jane Smith | jane@example.com | Apr 9, 18:42 |
48
+ | Bob Wilson | bob@example.com | Apr 9, 15:11 |
49
+ | Alice Chen | alice@example.com | Apr 8, 22:03 |
50
+ ... and 20 more.
51
+
52
+ User: Send a welcome notification to Jane
53
+
54
+ AI: I'll send a push notification to Jane's devices.
55
+
56
+ [calls auth_get_user with email: "jane@example.com"]
57
+ [calls messaging_send with:
58
+ topic: "user_jane_smith"
59
+ notification: { title: "Welcome!", body: "Thanks for joining us, Jane!" }
60
+ ]
61
+
62
+ Notification sent successfully! Message ID: projects/myapp/messages/123456
63
+
64
+ User: What's the schema of the orders collection?
65
+
66
+ AI: Let me infer the schema by sampling documents.
67
+
68
+ [calls firestore_infer_schema with:
69
+ collection: "orders"
70
+ sampleSize: 20
71
+ ]
72
+
73
+ Here's the inferred schema for `orders`:
74
+
75
+ | Field | Type | Presence | Nullable |
76
+ |-------------|----------|----------|----------|
77
+ | customerId | string | 100% | No |
78
+ | items | array | 100% | No |
79
+ | total | number | 100% | No |
80
+ | status | string | 95% | No |
81
+ | notes | string | 40% | Yes |
82
+ | shippedAt | timestamp| 60% | Yes |
83
+ ```
84
+
85
+ ---
86
+
87
+ ## Installation
88
+
89
+ ### Quick Start (Claude Desktop)
90
+
91
+ 1. Install the package globally:
92
+
93
+ ```bash
94
+ npm install -g mcp-server-firebase
95
+ ```
96
+
97
+ 2. Add to your Claude Desktop config (`~/AppData/Roaming/Claude/claude_desktop_config.json` on Windows or `~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
98
+
99
+ ```json
100
+ {
101
+ "mcpServers": {
102
+ "firebase": {
103
+ "command": "mcp-server-firebase",
104
+ "env": {
105
+ "FIREBASE_SERVICE_ACCOUNT_PATH": "/path/to/service-account-key.json"
106
+ }
107
+ }
108
+ }
109
+ }
110
+ ```
111
+
112
+ ### From Source
113
+
114
+ ```bash
115
+ git clone https://github.com/your-username/mcp-server-firebase.git
116
+ cd mcp-server-firebase
117
+ npm install
118
+ npm run build
119
+ ```
120
+
121
+ Then configure Claude Desktop to use the built version:
122
+
123
+ ```json
124
+ {
125
+ "mcpServers": {
126
+ "firebase": {
127
+ "command": "node",
128
+ "args": ["/path/to/mcp-server-firebase/dist/index.js"],
129
+ "env": {
130
+ "FIREBASE_SERVICE_ACCOUNT_PATH": "/path/to/service-account-key.json"
131
+ }
132
+ }
133
+ }
134
+ }
135
+ ```
136
+
137
+ ### Authentication Options
138
+
139
+ The server supports multiple ways to authenticate with Firebase:
140
+
141
+ | Method | Environment Variable | Description |
142
+ |--------|---------------------|-------------|
143
+ | Service Account JSON string | `FIREBASE_SERVICE_ACCOUNT_KEY` | Full JSON as a single-line string |
144
+ | Service Account file path | `FIREBASE_SERVICE_ACCOUNT_PATH` | Path to JSON key file |
145
+ | Individual fields | `FIREBASE_PROJECT_ID`, `FIREBASE_CLIENT_EMAIL`, `FIREBASE_PRIVATE_KEY` | Separate env vars |
146
+ | Application Default Credentials | _(none needed)_ | Works on GCP, with `gcloud auth` |
147
+
148
+ Optional configuration:
149
+
150
+ | Variable | Description | Default |
151
+ |----------|-------------|---------|
152
+ | `FIREBASE_STORAGE_BUCKET` | Cloud Storage bucket name | Auto-detected from project |
153
+ | `FIREBASE_DATABASE_URL` | Realtime Database URL | Auto-detected from project |
154
+ | `FIREBASE_FUNCTIONS_REGION` | Cloud Functions region | `us-central1` |
155
+
156
+ ---
157
+
158
+ ## Tools Reference
159
+
160
+ ### Firestore (13 tools)
161
+
162
+ | Tool | Description |
163
+ |------|-------------|
164
+ | `firestore_query` | Query collections with where, orderBy, limit, and pagination |
165
+ | `firestore_get_document` | Get a single document by path |
166
+ | `firestore_add_document` | Add a document with auto-generated ID |
167
+ | `firestore_set_document` | Create or overwrite a document (with optional merge) |
168
+ | `firestore_update_document` | Update specific fields (supports dot notation) |
169
+ | `firestore_delete_document` | Delete a document (optionally recursive) |
170
+ | `firestore_batch_write` | Atomic batch of up to 500 write operations |
171
+ | `firestore_transaction` | Read-then-write transaction for conditional updates |
172
+ | `firestore_list_collections` | List root collections or subcollections of a document |
173
+ | `firestore_list_subcollections` | List subcollections of a specific document |
174
+ | `firestore_aggregate_query` | Count, sum, average with optional filters |
175
+ | `firestore_listen_changes` | Listen for real-time changes (time-windowed) |
176
+ | `firestore_infer_schema` | Infer collection schema by sampling documents |
177
+
178
+ ### Auth (7 tools)
179
+
180
+ | Tool | Description |
181
+ |------|-------------|
182
+ | `auth_create_user` | Create a new user (email, phone, password, etc.) |
183
+ | `auth_get_user` | Get user by UID, email, or phone number |
184
+ | `auth_list_users` | List users with pagination |
185
+ | `auth_update_user` | Update user properties |
186
+ | `auth_delete_user` | Delete a user |
187
+ | `auth_verify_token` | Verify and decode a Firebase ID token |
188
+ | `auth_set_custom_claims` | Set RBAC claims on a user |
189
+
190
+ ### Storage (6 tools)
191
+
192
+ | Tool | Description |
193
+ |------|-------------|
194
+ | `storage_upload_file` | Upload a base64-encoded file |
195
+ | `storage_download_file` | Download a file (returns base64) |
196
+ | `storage_list_files` | List files with prefix filtering and pagination |
197
+ | `storage_delete_file` | Delete a file |
198
+ | `storage_get_signed_url` | Generate a time-limited signed URL |
199
+ | `storage_get_metadata` | Get file metadata (size, type, hashes) |
200
+
201
+ ### Realtime Database (6 tools)
202
+
203
+ | Tool | Description |
204
+ |------|-------------|
205
+ | `rtdb_get_data` | Read data at a path |
206
+ | `rtdb_set_data` | Overwrite data at a path |
207
+ | `rtdb_push_data` | Push to a list with auto-generated key |
208
+ | `rtdb_update_data` | Update specific fields without full overwrite |
209
+ | `rtdb_remove_data` | Remove data at a path |
210
+ | `rtdb_query_data` | Query with orderBy, filters, and limits |
211
+
212
+ ### Cloud Functions (3 tools)
213
+
214
+ | Tool | Description |
215
+ |------|-------------|
216
+ | `functions_list` | List deployed Cloud Functions |
217
+ | `functions_trigger` | Trigger an HTTP Cloud Function |
218
+ | `functions_get_logs` | Get recent logs for a function |
219
+
220
+ ### Messaging (4 tools)
221
+
222
+ | Tool | Description |
223
+ |------|-------------|
224
+ | `messaging_send` | Send a notification to a device, topic, or condition |
225
+ | `messaging_send_multicast` | Send to up to 500 devices at once |
226
+ | `messaging_subscribe_topic` | Subscribe tokens to a topic |
227
+ | `messaging_unsubscribe_topic` | Unsubscribe tokens from a topic |
228
+
229
+ ---
230
+
231
+ ## Query Builder Examples
232
+
233
+ ### Firestore Query with Multiple Filters
234
+
235
+ ```json
236
+ {
237
+ "collection": "orders",
238
+ "where": [
239
+ { "field": "status", "operator": "==", "value": "active" },
240
+ { "field": "total", "operator": ">", "value": 100 }
241
+ ],
242
+ "orderBy": [{ "field": "total", "direction": "desc" }],
243
+ "limit": 50
244
+ }
245
+ ```
246
+
247
+ ### Pagination
248
+
249
+ ```json
250
+ {
251
+ "collection": "products",
252
+ "limit": 100,
253
+ "pageToken": "cHJvZHVjdHMvcHJvZDEyMw=="
254
+ }
255
+ ```
256
+
257
+ ### Aggregation
258
+
259
+ ```json
260
+ {
261
+ "collection": "orders",
262
+ "aggregations": [
263
+ { "type": "count", "alias": "totalOrders" },
264
+ { "type": "sum", "field": "total", "alias": "revenue" },
265
+ { "type": "avg", "field": "total", "alias": "averageOrder" }
266
+ ],
267
+ "where": [
268
+ { "field": "status", "operator": "==", "value": "completed" }
269
+ ]
270
+ }
271
+ ```
272
+
273
+ ### Realtime DB Query
274
+
275
+ ```json
276
+ {
277
+ "path": "/scores",
278
+ "orderBy": { "child": "score" },
279
+ "limitToLast": 10
280
+ }
281
+ ```
282
+
283
+ ---
284
+
285
+ ## Security
286
+
287
+ This server is designed with security as a priority:
288
+
289
+ - **Service account key via environment variable** -- never hardcoded or committed
290
+ - **Input validation** on every parameter (paths, emails, UIDs, limits)
291
+ - **NoSQL injection prevention** -- field names starting with `$` or containing `.` are rejected
292
+ - **Path traversal prevention** -- storage paths with `..` or leading `/` are blocked
293
+ - **Field name restrictions** -- where clause fields starting with `__` are rejected
294
+ - **Custom claims size limit** -- enforces Firebase's 1000-byte limit
295
+ - **Reserved claim keys** -- prevents overwriting standard JWT claims
296
+ - **Batch operation limits** -- caps at 500 operations per batch
297
+ - **Signed URL limits** -- minimum 60s, maximum 7 days validity
298
+
299
+ ---
300
+
301
+ ## Development
302
+
303
+ ```bash
304
+ # Install dependencies
305
+ npm install
306
+
307
+ # Build
308
+ npm run build
309
+
310
+ # Run tests
311
+ npm test
312
+
313
+ # Run tests in watch mode
314
+ npm run test:watch
315
+
316
+ # Run with coverage
317
+ npm run test:coverage
318
+
319
+ # Type check
320
+ npm run lint
321
+
322
+ # Run locally
323
+ npm run dev
324
+ ```
325
+
326
+ ### Project Structure
327
+
328
+ ```
329
+ src/
330
+ index.ts # MCP server entry point
331
+ services/
332
+ firebase.ts # Firebase Admin SDK initialization
333
+ tools/
334
+ types.ts # ToolDefinition interface
335
+ index.ts # Tool aggregation and export
336
+ firestore.ts # 13 Firestore tools
337
+ auth.ts # 7 Auth tools
338
+ storage.ts # 6 Storage tools
339
+ realtime-db.ts # 6 Realtime DB tools
340
+ functions.ts # 3 Cloud Functions tools
341
+ messaging.ts # 4 FCM Messaging tools
342
+ utils/
343
+ index.ts # Re-exports
344
+ validation.ts # Input validation and sanitization
345
+ errors.ts # Error handling with fix suggestions
346
+ cache.ts # LRU cache with TTL and prefix invalidation
347
+ pagination.ts # Cursor-based pagination utilities
348
+ tests/
349
+ validation.test.ts # Validation tests (16 tests)
350
+ errors.test.ts # Error handling tests (10 tests)
351
+ cache.test.ts # Cache tests (12 tests)
352
+ pagination.test.ts # Pagination tests (4 tests)
353
+ tools.test.ts # Tool registration and validation tests (30+ tests)
354
+ firebase-service.test.ts # RTDB path validation tests
355
+ vitest.config.ts
356
+ ```
357
+
358
+ ---
359
+
360
+ ## License
361
+
362
+ MIT
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
5
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
6
+ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
7
+ const firebase_js_1 = require("./services/firebase.js");
8
+ const index_js_2 = require("./tools/index.js");
9
+ const SERVER_NAME = 'mcp-server-firebase';
10
+ const SERVER_VERSION = '1.0.0';
11
+ async function main() {
12
+ // Validate Firebase configuration on startup
13
+ try {
14
+ (0, firebase_js_1.initializeFirebase)();
15
+ }
16
+ catch (err) {
17
+ console.error(`Failed to initialize Firebase: ${err.message}\n` +
18
+ 'Ensure one of the following is set:\n' +
19
+ ' - FIREBASE_SERVICE_ACCOUNT_KEY (JSON string)\n' +
20
+ ' - FIREBASE_SERVICE_ACCOUNT_PATH (file path)\n' +
21
+ ' - FIREBASE_PROJECT_ID + FIREBASE_CLIENT_EMAIL + FIREBASE_PRIVATE_KEY\n' +
22
+ ' - Application Default Credentials (gcloud auth application-default login)');
23
+ process.exit(1);
24
+ }
25
+ // Create MCP server using the low-level Server class
26
+ // This allows us to register tools with raw JSON Schema input schemas
27
+ const server = new index_js_1.Server({ name: SERVER_NAME, version: SERVER_VERSION }, {
28
+ capabilities: {
29
+ tools: {},
30
+ },
31
+ });
32
+ // Build a map for quick tool lookup
33
+ const toolMap = new Map(index_js_2.allTools.map((t) => [t.name, t]));
34
+ // Handle tools/list requests
35
+ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
36
+ return {
37
+ tools: index_js_2.allTools.map((tool) => ({
38
+ name: tool.name,
39
+ description: tool.description,
40
+ inputSchema: tool.inputSchema,
41
+ })),
42
+ };
43
+ });
44
+ // Handle tools/call requests
45
+ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
46
+ const toolName = request.params.name;
47
+ const tool = toolMap.get(toolName);
48
+ if (!tool) {
49
+ return {
50
+ content: [{ type: 'text', text: `Error: Unknown tool "${toolName}".` }],
51
+ isError: true,
52
+ };
53
+ }
54
+ try {
55
+ const args = request.params.arguments ?? {};
56
+ const result = await tool.handler(args);
57
+ return {
58
+ content: [{ type: 'text', text: result }],
59
+ };
60
+ }
61
+ catch (err) {
62
+ const message = err instanceof Error ? err.message : String(err);
63
+ return {
64
+ content: [{ type: 'text', text: `Error: ${message}` }],
65
+ isError: true,
66
+ };
67
+ }
68
+ });
69
+ // Connect using stdio transport
70
+ const transport = new stdio_js_1.StdioServerTransport();
71
+ await server.connect(transport);
72
+ console.error(`${SERVER_NAME} v${SERVER_VERSION} running on stdio`);
73
+ console.error(`Registered ${index_js_2.allTools.length} tools`);
74
+ }
75
+ main().catch((err) => {
76
+ console.error('Fatal error:', err);
77
+ process.exit(1);
78
+ });
79
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,14 @@
1
+ import * as admin from 'firebase-admin';
2
+ export interface FirebaseConfig {
3
+ projectId?: string;
4
+ storageBucket?: string;
5
+ databaseURL?: string;
6
+ }
7
+ export declare function initializeFirebase(config?: FirebaseConfig): admin.app.App;
8
+ export declare function getFirestore(): admin.firestore.Firestore;
9
+ export declare function getAuth(): admin.auth.Auth;
10
+ export declare function getStorage(): admin.storage.Storage;
11
+ export declare function getRealtimeDb(): admin.database.Database;
12
+ export declare function getMessaging(): admin.messaging.Messaging;
13
+ export declare function getApp(): admin.app.App;
14
+ //# sourceMappingURL=firebase.d.ts.map
@@ -0,0 +1,163 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.initializeFirebase = initializeFirebase;
40
+ exports.getFirestore = getFirestore;
41
+ exports.getAuth = getAuth;
42
+ exports.getStorage = getStorage;
43
+ exports.getRealtimeDb = getRealtimeDb;
44
+ exports.getMessaging = getMessaging;
45
+ exports.getApp = getApp;
46
+ const admin = __importStar(require("firebase-admin"));
47
+ const fs_1 = __importDefault(require("fs"));
48
+ let app = null;
49
+ function getServiceAccount() {
50
+ // 1. Try FIREBASE_SERVICE_ACCOUNT_KEY (JSON string)
51
+ const keyEnv = process.env['FIREBASE_SERVICE_ACCOUNT_KEY'];
52
+ if (keyEnv) {
53
+ try {
54
+ return JSON.parse(keyEnv);
55
+ }
56
+ catch {
57
+ throw new Error('FIREBASE_SERVICE_ACCOUNT_KEY is set but contains invalid JSON. ' +
58
+ 'Provide the full service account JSON as a single-line string.');
59
+ }
60
+ }
61
+ // 2. Try FIREBASE_SERVICE_ACCOUNT_PATH (file path)
62
+ const pathEnv = process.env['FIREBASE_SERVICE_ACCOUNT_PATH'];
63
+ if (pathEnv) {
64
+ try {
65
+ const content = fs_1.default.readFileSync(pathEnv, 'utf-8');
66
+ return JSON.parse(content);
67
+ }
68
+ catch (err) {
69
+ throw new Error(`Failed to read service account file at "${pathEnv}": ${err.message}. ` +
70
+ 'Ensure the path is correct and the file is valid JSON.');
71
+ }
72
+ }
73
+ // 3. Try individual env vars
74
+ const projectId = process.env['FIREBASE_PROJECT_ID'];
75
+ const clientEmail = process.env['FIREBASE_CLIENT_EMAIL'];
76
+ const privateKey = process.env['FIREBASE_PRIVATE_KEY']?.replace(/\\n/g, '\n');
77
+ if (projectId && clientEmail && privateKey) {
78
+ return { projectId, clientEmail, privateKey };
79
+ }
80
+ // 4. Return undefined — rely on Application Default Credentials (ADC)
81
+ return undefined;
82
+ }
83
+ function initializeFirebase(config) {
84
+ if (app) {
85
+ return app;
86
+ }
87
+ const serviceAccount = getServiceAccount();
88
+ const initOptions = {};
89
+ if (serviceAccount) {
90
+ initOptions.credential = admin.credential.cert(serviceAccount);
91
+ }
92
+ // If no service account, ADC will be used (works on GCP, with gcloud CLI, etc.)
93
+ if (config?.projectId) {
94
+ initOptions.projectId = config.projectId;
95
+ }
96
+ else if (serviceAccount?.projectId) {
97
+ initOptions.projectId = serviceAccount.projectId;
98
+ }
99
+ else {
100
+ const envProject = process.env['FIREBASE_PROJECT_ID'];
101
+ if (envProject) {
102
+ initOptions.projectId = envProject;
103
+ }
104
+ }
105
+ if (config?.storageBucket) {
106
+ initOptions.storageBucket = config.storageBucket;
107
+ }
108
+ else {
109
+ const envBucket = process.env['FIREBASE_STORAGE_BUCKET'];
110
+ if (envBucket) {
111
+ initOptions.storageBucket = envBucket;
112
+ }
113
+ }
114
+ if (config?.databaseURL) {
115
+ initOptions.databaseURL = config.databaseURL;
116
+ }
117
+ else {
118
+ const envDbUrl = process.env['FIREBASE_DATABASE_URL'];
119
+ if (envDbUrl) {
120
+ initOptions.databaseURL = envDbUrl;
121
+ }
122
+ }
123
+ try {
124
+ app = admin.initializeApp(initOptions, 'mcp-firebase-server');
125
+ }
126
+ catch (err) {
127
+ // If app already exists, get it
128
+ if (err instanceof Error && err.message.includes('already exists')) {
129
+ app = admin.app('mcp-firebase-server');
130
+ }
131
+ else {
132
+ throw err;
133
+ }
134
+ }
135
+ return app;
136
+ }
137
+ function getFirestore() {
138
+ const firebaseApp = initializeFirebase();
139
+ return firebaseApp.firestore();
140
+ }
141
+ function getAuth() {
142
+ const firebaseApp = initializeFirebase();
143
+ return firebaseApp.auth();
144
+ }
145
+ function getStorage() {
146
+ const firebaseApp = initializeFirebase();
147
+ return firebaseApp.storage();
148
+ }
149
+ function getRealtimeDb() {
150
+ const firebaseApp = initializeFirebase();
151
+ return firebaseApp.database();
152
+ }
153
+ function getMessaging() {
154
+ const firebaseApp = initializeFirebase();
155
+ return firebaseApp.messaging();
156
+ }
157
+ function getApp() {
158
+ if (!app) {
159
+ return initializeFirebase();
160
+ }
161
+ return app;
162
+ }
163
+ //# sourceMappingURL=firebase.js.map
@@ -0,0 +1,3 @@
1
+ import type { ToolDefinition } from './types.js';
2
+ export declare const authTools: ToolDefinition[];
3
+ //# sourceMappingURL=auth.d.ts.map