firebase-mcp 0.3.1 → 0.3.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
@@ -4,39 +4,53 @@ A [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server that ex
4
4
 
5
5
  ## Features
6
6
 
7
- - **11 Firestore read tools** covering collections, documents, queries, aggregations, and schema inference
8
- - **2 Firebase Auth tools** — look up users by UID or email, list users with pagination
7
+ - **12 Firestore read operations** covering collections, documents, queries, aggregations, distinct value counts, and schema inference
8
+ - **2 Firebase Auth operations** — look up users by UID or email, list users with pagination
9
+ - **Multi-project support** — configure multiple Firebase projects in one config file; each tool call targets a specific project via `projectId`
9
10
  - **Glob-based access control** — allow/deny rules evaluated per Firestore path before any read is performed
10
11
  - **Pagination** on `query_collection`, `read_collection`, and `list_users` via cursor-based tokens
11
12
  - **Batch fetching** with configurable `maxBatchFetchSize`
12
13
  - **Schema inference** via `get_collection_schema` — samples documents and infers field types without reading the full collection
14
+ - **Distinct value counts** via `distinct_values` — count occurrences of unique field values across a collection or collection group
13
15
  - **Normalized output** — Firestore Timestamps, GeoPoints, and DocumentReferences are converted to JSON-serializable values on all tools
14
16
  - Zero runtime state — each tool call hits Firebase directly through the Admin SDK
15
17
 
16
18
  ## Tools
17
19
 
18
- ### Firestore
19
-
20
- | Tool | Description |
21
- | ------------------------ | ----------------------------------------------------------------------------------------------------------- |
22
- | `list_collections` | List root collections or subcollections of a document. Optionally include document counts. |
23
- | `list_documents` | List all document IDs in a collection, including phantom documents. Optionally include subcollection names. |
24
- | `read_collection` | Read documents from a collection with optional phantom-doc surfacing. |
25
- | `get_document` | Fetch a single document by path. |
26
- | `get_many_documents` | Batch-fetch documents by a list of paths or a collection + ID list. |
27
- | `query_collection` | Query with filters, ordering, limit, and pagination. |
28
- | `query_collection_group` | Query across all collections sharing the same name, regardless of parent path. |
29
- | `count_documents` | Server-side document count with optional filters. |
30
- | `aggregate_collection` | Native `sum()` and `avg()` aggregations without fetching documents. |
31
- | `get_collection_schema` | Sample a collection from both ends and infer field types. |
32
- | `list_indexes` | List Firestore indexes for the project. |
33
-
34
- ### Auth
35
-
36
- | Tool | Description |
37
- | ------------ | ---------------------------------------------------------------------- |
38
- | `get_user` | Fetch a Firebase Auth user by UID or email. |
39
- | `list_users` | List Firebase Auth users with optional pagination via `nextPageToken`. |
20
+ ### Config
21
+
22
+ | Tool | Description |
23
+ | --------------- | --------------------------------------------------------------------------------------------------------------------------- |
24
+ | `get_config` | Returns the current in-memory config, listing all available projects. Call this first to discover valid `projectId` values. |
25
+ | `reload_config` | Re-reads `firebase-mcp.json` from disk and evicts all cached project runtimes. |
26
+
27
+ ### Firestore (`firestore_read`)
28
+
29
+ All operations are dispatched through the single `firestore_read` tool via the `operation` field. Every call requires a `projectId` matching a key in `firebase-mcp.json`.
30
+
31
+ | Operation | Description |
32
+ | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
33
+ | `list_collections` | List root collections or subcollections of a document. Optionally include document counts. |
34
+ | `list_documents` | List all document IDs in a collection, including phantom documents. Optionally include subcollection names. |
35
+ | `read_collection` | Read documents from a collection with optional phantom-doc surfacing. |
36
+ | `get_document` | Fetch a single document by path. |
37
+ | `get_many_documents` | Batch-fetch documents by a list of paths or a collection + ID list. |
38
+ | `query_collection` | Query with filters, ordering, limit, and pagination. |
39
+ | `query_collection_group` | Query across all collections sharing the same name, regardless of parent path. |
40
+ | `count_documents` | Server-side document count with optional filters. |
41
+ | `aggregate_collection` | Native `sum()`, `avg()`, and `count()` aggregations without fetching documents. |
42
+ | `get_collection_schema` | Sample a collection from both ends and infer field types. |
43
+ | `list_indexes` | List Firestore composite indexes for the project. |
44
+ | `distinct_values` | Count occurrences of each unique value (or value combination) of one or more fields across a collection or collection group. |
45
+
46
+ ### Auth (`auth_read`)
47
+
48
+ All operations are dispatched through the single `auth_read` tool via the `operation` field. Every call requires a `projectId`.
49
+
50
+ | Operation | Description |
51
+ | ------------ | ------------------------------------------------------------------ |
52
+ | `get_user` | Fetch a Firebase Auth user by UID or email. |
53
+ | `list_users` | List Firebase Auth users with optional pagination via `pageToken`. |
40
54
 
41
55
  ## Requirements
42
56
 
@@ -48,26 +62,43 @@ A [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server that ex
48
62
 
49
63
  **1. Create `firebase-mcp.json`**
50
64
 
65
+ The config supports multiple projects under a `projects` key. Each key becomes the `projectId` value you pass to tool calls.
66
+
51
67
  ```json
52
68
  {
53
- "firebase": {
54
- "projectId": "your-project-id",
55
- "serviceAccountPath": "secrets/serviceAccount.json"
56
- },
57
- "firestore": {
58
- "rules": {
59
- "allow": ["**"],
60
- "deny": []
61
- },
62
- "maxCollectionReadSize": 10,
63
- "maxBatchFetchSize": 200
69
+ "projects": {
70
+ "my-app": {
71
+ "firebase": {
72
+ "projectId": "your-firebase-project-id",
73
+ "serviceAccountPath": "secrets/serviceAccount.json"
74
+ },
75
+ "firestore": {
76
+ "rules": {
77
+ "allow": ["**"],
78
+ "deny": []
79
+ },
80
+ "maxCollectionReadSize": 100,
81
+ "maxBatchFetchSize": 200
82
+ }
83
+ }
84
+ }
85
+ }
86
+ ```
87
+
88
+ To configure multiple projects, add additional keys under `projects`:
89
+
90
+ ```json
91
+ {
92
+ "projects": {
93
+ "prod": { "firebase": { ... }, "firestore": { ... } },
94
+ "staging": { "firebase": { ... }, "firestore": { ... } }
64
95
  }
65
96
  }
66
97
  ```
67
98
 
68
99
  **2. Add your service account key**
69
100
 
70
- Place your Firebase service account JSON at any path you prefer — you'll reference it in `firebase-mcp.json` above.
101
+ Place your Firebase service account JSON at any path you prefer — you'll reference it in `firebase-mcp.json` above. Paths are resolved relative to the working directory when the server starts, or you can use an absolute path.
71
102
 
72
103
  **3. Wire it into your MCP host**
73
104
 
@@ -75,14 +106,15 @@ See the [Connecting to Cursor](#connecting-to-cursor) section below — no insta
75
106
 
76
107
  ## Configuration
77
108
 
78
- | Field | Type | Default | Description |
79
- | --------------------------------- | ---------- | ------- | ---------------------------------------------------------- |
80
- | `firebase.projectId` | `string` | — | Firebase project ID |
81
- | `firebase.serviceAccountPath` | `string` | — | Path to service account JSON (relative to CWD or absolute) |
82
- | `firestore.rules.allow` | `string[]` | — | Glob patterns for allowed Firestore paths |
83
- | `firestore.rules.deny` | `string[]` | — | Glob patterns for denied Firestore paths (evaluated first) |
84
- | `firestore.maxCollectionReadSize` | `number` | `10` | Default document limit for collection reads |
85
- | `firestore.maxBatchFetchSize` | `number` | `200` | Maximum documents per batch fetch |
109
+ | Field | Type | Default | Description |
110
+ | ------------------------------------------------ | ---------- | ------- | ---------------------------------------------------------- |
111
+ | `projects` | `object` | — | Map of project keys to project configs |
112
+ | `projects.<key>.firebase.projectId` | `string` | — | Firebase project ID |
113
+ | `projects.<key>.firebase.serviceAccountPath` | `string` | — | Path to service account JSON (relative to CWD or absolute) |
114
+ | `projects.<key>.firestore.rules.allow` | `string[]` | — | Glob patterns for allowed Firestore paths |
115
+ | `projects.<key>.firestore.rules.deny` | `string[]` | | Glob patterns for denied Firestore paths (evaluated first) |
116
+ | `projects.<key>.firestore.maxCollectionReadSize` | `number` | `100` | Default document limit for collection reads |
117
+ | `projects.<key>.firestore.maxBatchFetchSize` | `number` | `200` | Maximum documents per batch fetch |
86
118
 
87
119
  A custom config path can be passed at startup:
88
120
 
@@ -120,6 +152,8 @@ Add to your MCP config (e.g. `.cursor/mcp.json`):
120
152
 
121
153
  `npx -y` will download and cache the package automatically on first run. No manual installation needed.
122
154
 
155
+ `firestore_read` and `auth_read` are safe to add to Cursor's tool allowlist for unattended use. `get_config` and `reload_config` are also read-only and safe to allowlist.
156
+
123
157
  ## License
124
158
 
125
159
  MIT
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../src/config/index.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const index_1 = require("./index");
5
+ // ---------------------------------------------------------------------------
6
+ // ProjectConfigSchema — the innermost validated unit, no file I/O needed
7
+ // ---------------------------------------------------------------------------
8
+ const validProject = {
9
+ firebase: {
10
+ projectId: 'my-project',
11
+ serviceAccountPath: '/path/to/sa.json',
12
+ },
13
+ firestore: {
14
+ rules: {
15
+ allow: ['**'],
16
+ deny: [],
17
+ },
18
+ },
19
+ };
20
+ (0, vitest_1.describe)('ProjectConfigSchema', () => {
21
+ (0, vitest_1.it)('parses a fully valid project config', () => {
22
+ const result = index_1.ProjectConfigSchema.safeParse(validProject);
23
+ (0, vitest_1.expect)(result.success).toBe(true);
24
+ });
25
+ (0, vitest_1.it)('applies default maxCollectionReadSize of 100', () => {
26
+ const result = index_1.ProjectConfigSchema.safeParse(validProject);
27
+ (0, vitest_1.expect)(result.success).toBe(true);
28
+ if (result.success) {
29
+ (0, vitest_1.expect)(result.data.firestore.maxCollectionReadSize).toBe(100);
30
+ }
31
+ });
32
+ (0, vitest_1.it)('applies default maxBatchFetchSize of 200', () => {
33
+ const result = index_1.ProjectConfigSchema.safeParse(validProject);
34
+ (0, vitest_1.expect)(result.success).toBe(true);
35
+ if (result.success) {
36
+ (0, vitest_1.expect)(result.data.firestore.maxBatchFetchSize).toBe(200);
37
+ }
38
+ });
39
+ (0, vitest_1.it)('accepts explicit maxCollectionReadSize and maxBatchFetchSize', () => {
40
+ const input = {
41
+ ...validProject,
42
+ firestore: {
43
+ ...validProject.firestore,
44
+ maxCollectionReadSize: 50,
45
+ maxBatchFetchSize: 75,
46
+ },
47
+ };
48
+ const result = index_1.ProjectConfigSchema.safeParse(input);
49
+ (0, vitest_1.expect)(result.success).toBe(true);
50
+ if (result.success) {
51
+ (0, vitest_1.expect)(result.data.firestore.maxCollectionReadSize).toBe(50);
52
+ (0, vitest_1.expect)(result.data.firestore.maxBatchFetchSize).toBe(75);
53
+ }
54
+ });
55
+ (0, vitest_1.it)('fails when firebase.projectId is missing', () => {
56
+ const input = {
57
+ ...validProject,
58
+ firebase: { serviceAccountPath: '/path/to/sa.json' },
59
+ };
60
+ const result = index_1.ProjectConfigSchema.safeParse(input);
61
+ (0, vitest_1.expect)(result.success).toBe(false);
62
+ });
63
+ (0, vitest_1.it)('fails when firebase.serviceAccountPath is missing', () => {
64
+ const input = {
65
+ ...validProject,
66
+ firebase: { projectId: 'my-project' },
67
+ };
68
+ const result = index_1.ProjectConfigSchema.safeParse(input);
69
+ (0, vitest_1.expect)(result.success).toBe(false);
70
+ });
71
+ (0, vitest_1.it)('fails when firestore.rules is missing', () => {
72
+ const input = { ...validProject, firestore: {} };
73
+ const result = index_1.ProjectConfigSchema.safeParse(input);
74
+ (0, vitest_1.expect)(result.success).toBe(false);
75
+ });
76
+ (0, vitest_1.it)('fails when firestore.rules.allow is not an array', () => {
77
+ const input = {
78
+ ...validProject,
79
+ firestore: { rules: { allow: '**', deny: [] } },
80
+ };
81
+ const result = index_1.ProjectConfigSchema.safeParse(input);
82
+ (0, vitest_1.expect)(result.success).toBe(false);
83
+ });
84
+ (0, vitest_1.it)('fails when firestore.rules.deny is not an array', () => {
85
+ const input = {
86
+ ...validProject,
87
+ firestore: { rules: { allow: ['**'], deny: 'none' } },
88
+ };
89
+ const result = index_1.ProjectConfigSchema.safeParse(input);
90
+ (0, vitest_1.expect)(result.success).toBe(false);
91
+ });
92
+ (0, vitest_1.it)('fails when the top-level object is missing', () => {
93
+ (0, vitest_1.expect)(index_1.ProjectConfigSchema.safeParse(null).success).toBe(false);
94
+ (0, vitest_1.expect)(index_1.ProjectConfigSchema.safeParse(undefined).success).toBe(false);
95
+ (0, vitest_1.expect)(index_1.ProjectConfigSchema.safeParse('string').success).toBe(false);
96
+ });
97
+ });
98
+ //# sourceMappingURL=index.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../src/config/index.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../src/task/index.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,318 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const index_1 = require("./index");
5
+ // ---------------------------------------------------------------------------
6
+ // Exit constructors & guards
7
+ // ---------------------------------------------------------------------------
8
+ (0, vitest_1.describe)('Exit', () => {
9
+ (0, vitest_1.describe)('constructors', () => {
10
+ (0, vitest_1.it)('ok wraps a value', () => {
11
+ const e = index_1.Exit.ok(42);
12
+ (0, vitest_1.expect)(e._tag).toBe('ok');
13
+ (0, vitest_1.expect)(e.value).toBe(42);
14
+ });
15
+ (0, vitest_1.it)('err wraps an error', () => {
16
+ const e = index_1.Exit.err('boom');
17
+ (0, vitest_1.expect)(e._tag).toBe('err');
18
+ (0, vitest_1.expect)(e.error).toBe('boom');
19
+ });
20
+ (0, vitest_1.it)('die wraps an optional cause', () => {
21
+ (0, vitest_1.expect)(index_1.Exit.die()._tag).toBe('die');
22
+ const e = index_1.Exit.die(new Error('oops'));
23
+ (0, vitest_1.expect)(e._tag).toBe('die');
24
+ (0, vitest_1.expect)(e.cause).toBeInstanceOf(Error);
25
+ });
26
+ });
27
+ (0, vitest_1.describe)('guards', () => {
28
+ (0, vitest_1.it)('isOk returns true only for ok exits', () => {
29
+ (0, vitest_1.expect)(index_1.Exit.isOk(index_1.Exit.ok(1))).toBe(true);
30
+ (0, vitest_1.expect)(index_1.Exit.isOk(index_1.Exit.err('e'))).toBe(false);
31
+ (0, vitest_1.expect)(index_1.Exit.isOk(index_1.Exit.die())).toBe(false);
32
+ });
33
+ (0, vitest_1.it)('isErr returns true only for err exits', () => {
34
+ (0, vitest_1.expect)(index_1.Exit.isErr(index_1.Exit.err('e'))).toBe(true);
35
+ (0, vitest_1.expect)(index_1.Exit.isErr(index_1.Exit.ok(1))).toBe(false);
36
+ (0, vitest_1.expect)(index_1.Exit.isErr(index_1.Exit.die())).toBe(false);
37
+ });
38
+ (0, vitest_1.it)('isDie returns true only for die exits', () => {
39
+ (0, vitest_1.expect)(index_1.Exit.isDie(index_1.Exit.die())).toBe(true);
40
+ (0, vitest_1.expect)(index_1.Exit.isDie(index_1.Exit.ok(1))).toBe(false);
41
+ (0, vitest_1.expect)(index_1.Exit.isDie(index_1.Exit.err('e'))).toBe(false);
42
+ });
43
+ });
44
+ });
45
+ // ---------------------------------------------------------------------------
46
+ // Helpers
47
+ // ---------------------------------------------------------------------------
48
+ async function run(task) {
49
+ const { exit } = task.fork();
50
+ return exit;
51
+ }
52
+ // ---------------------------------------------------------------------------
53
+ // Task static constructors
54
+ // ---------------------------------------------------------------------------
55
+ (0, vitest_1.describe)('Task.succeed', () => {
56
+ (0, vitest_1.it)('resolves to ok', async () => {
57
+ const exit = await run(index_1.Task.succeed(99));
58
+ (0, vitest_1.expect)(index_1.Exit.isOk(exit)).toBe(true);
59
+ if (index_1.Exit.isOk(exit))
60
+ (0, vitest_1.expect)(exit.value).toBe(99);
61
+ });
62
+ });
63
+ (0, vitest_1.describe)('Task.fail', () => {
64
+ (0, vitest_1.it)('resolves to err', async () => {
65
+ const exit = await run(index_1.Task.fail('reason'));
66
+ (0, vitest_1.expect)(index_1.Exit.isErr(exit)).toBe(true);
67
+ if (index_1.Exit.isErr(exit))
68
+ (0, vitest_1.expect)(exit.error).toBe('reason');
69
+ });
70
+ });
71
+ (0, vitest_1.describe)('Task.die', () => {
72
+ (0, vitest_1.it)('resolves to die', async () => {
73
+ const exit = await run(index_1.Task.die('cause'));
74
+ (0, vitest_1.expect)(index_1.Exit.isDie(exit)).toBe(true);
75
+ if (index_1.Exit.isDie(exit))
76
+ (0, vitest_1.expect)(exit.cause).toBe('cause');
77
+ });
78
+ });
79
+ (0, vitest_1.describe)('Task.sync', () => {
80
+ (0, vitest_1.it)('wraps a synchronous value', async () => {
81
+ const exit = await run(index_1.Task.sync(() => 'hello'));
82
+ (0, vitest_1.expect)(index_1.Exit.isOk(exit)).toBe(true);
83
+ if (index_1.Exit.isOk(exit))
84
+ (0, vitest_1.expect)(exit.value).toBe('hello');
85
+ });
86
+ (0, vitest_1.it)('converts a thrown error to die', async () => {
87
+ const exit = await run(index_1.Task.sync(() => { throw new Error('sync boom'); }));
88
+ (0, vitest_1.expect)(index_1.Exit.isDie(exit)).toBe(true);
89
+ });
90
+ });
91
+ (0, vitest_1.describe)('Task.lazy', () => {
92
+ (0, vitest_1.it)('defers construction until run', async () => {
93
+ let constructed = false;
94
+ const task = index_1.Task.lazy(() => {
95
+ constructed = true;
96
+ return index_1.Task.succeed(1);
97
+ });
98
+ (0, vitest_1.expect)(constructed).toBe(false);
99
+ await run(task);
100
+ (0, vitest_1.expect)(constructed).toBe(true);
101
+ });
102
+ });
103
+ (0, vitest_1.describe)('Task.attempt', () => {
104
+ (0, vitest_1.it)('resolves to ok when the factory succeeds', async () => {
105
+ const exit = await run(index_1.Task.attempt({
106
+ try: () => Promise.resolve('done'),
107
+ catch: (e) => e,
108
+ }));
109
+ (0, vitest_1.expect)(index_1.Exit.isOk(exit)).toBe(true);
110
+ if (index_1.Exit.isOk(exit))
111
+ (0, vitest_1.expect)(exit.value).toBe('done');
112
+ });
113
+ (0, vitest_1.it)('resolves to err when the factory throws', async () => {
114
+ const exit = await run(index_1.Task.attempt({
115
+ try: () => { throw new Error('fail'); },
116
+ catch: (e) => ({ mapped: true, cause: e }),
117
+ }));
118
+ (0, vitest_1.expect)(index_1.Exit.isErr(exit)).toBe(true);
119
+ if (index_1.Exit.isErr(exit))
120
+ (0, vitest_1.expect)(exit.error.mapped).toBe(true);
121
+ });
122
+ (0, vitest_1.it)('resolves to err when the promise rejects', async () => {
123
+ const exit = await run(index_1.Task.attempt({
124
+ try: () => Promise.reject(new Error('async fail')),
125
+ catch: (e) => String(e),
126
+ }));
127
+ (0, vitest_1.expect)(index_1.Exit.isErr(exit)).toBe(true);
128
+ });
129
+ });
130
+ // ---------------------------------------------------------------------------
131
+ // Task instance combinators
132
+ // ---------------------------------------------------------------------------
133
+ (0, vitest_1.describe)('Task#map', () => {
134
+ (0, vitest_1.it)('transforms the ok value', async () => {
135
+ const exit = await run(index_1.Task.succeed(3).map((n) => n * 2));
136
+ (0, vitest_1.expect)(index_1.Exit.isOk(exit)).toBe(true);
137
+ if (index_1.Exit.isOk(exit))
138
+ (0, vitest_1.expect)(exit.value).toBe(6);
139
+ });
140
+ (0, vitest_1.it)('passes err through unchanged', async () => {
141
+ const exit = await run(index_1.Task.fail('e').map((n) => n * 2));
142
+ (0, vitest_1.expect)(index_1.Exit.isErr(exit)).toBe(true);
143
+ if (index_1.Exit.isErr(exit))
144
+ (0, vitest_1.expect)(exit.error).toBe('e');
145
+ });
146
+ (0, vitest_1.it)('converts a mapper throw to die', async () => {
147
+ const exit = await run(index_1.Task.succeed(1).map(() => { throw new Error('map boom'); }));
148
+ (0, vitest_1.expect)(index_1.Exit.isDie(exit)).toBe(true);
149
+ });
150
+ });
151
+ (0, vitest_1.describe)('Task#flatMap', () => {
152
+ (0, vitest_1.it)('chains a successful continuation', async () => {
153
+ const exit = await run(index_1.Task.succeed(5).flatMap((n) => index_1.Task.succeed(n + 1)));
154
+ (0, vitest_1.expect)(index_1.Exit.isOk(exit)).toBe(true);
155
+ if (index_1.Exit.isOk(exit))
156
+ (0, vitest_1.expect)(exit.value).toBe(6);
157
+ });
158
+ (0, vitest_1.it)('short-circuits on err', async () => {
159
+ let ran = false;
160
+ const exit = await run(index_1.Task.fail('original').flatMap(() => {
161
+ ran = true;
162
+ return index_1.Task.succeed(42);
163
+ }));
164
+ (0, vitest_1.expect)(ran).toBe(false);
165
+ (0, vitest_1.expect)(index_1.Exit.isErr(exit)).toBe(true);
166
+ });
167
+ (0, vitest_1.it)('can chain to a failing task', async () => {
168
+ const exit = await run(index_1.Task.succeed(1).flatMap(() => index_1.Task.fail('chained error')));
169
+ (0, vitest_1.expect)(index_1.Exit.isErr(exit)).toBe(true);
170
+ if (index_1.Exit.isErr(exit))
171
+ (0, vitest_1.expect)(exit.error).toBe('chained error');
172
+ });
173
+ });
174
+ (0, vitest_1.describe)('Task#tap', () => {
175
+ (0, vitest_1.it)('runs a side effect and preserves the value', async () => {
176
+ let seen;
177
+ const exit = await run(index_1.Task.succeed(7).tap((n) => { seen = n; }));
178
+ (0, vitest_1.expect)(seen).toBe(7);
179
+ (0, vitest_1.expect)(index_1.Exit.isOk(exit)).toBe(true);
180
+ if (index_1.Exit.isOk(exit))
181
+ (0, vitest_1.expect)(exit.value).toBe(7);
182
+ });
183
+ (0, vitest_1.it)('skips the side effect on err', async () => {
184
+ let ran = false;
185
+ await run(index_1.Task.fail('e').tap(() => { ran = true; }));
186
+ (0, vitest_1.expect)(ran).toBe(false);
187
+ });
188
+ });
189
+ (0, vitest_1.describe)('Task#mapError', () => {
190
+ (0, vitest_1.it)('transforms the error', async () => {
191
+ const exit = await run(index_1.Task.fail(1).mapError((n) => n * 10));
192
+ (0, vitest_1.expect)(index_1.Exit.isErr(exit)).toBe(true);
193
+ if (index_1.Exit.isErr(exit))
194
+ (0, vitest_1.expect)(exit.error).toBe(10);
195
+ });
196
+ (0, vitest_1.it)('passes ok through', async () => {
197
+ const exit = await run(index_1.Task.succeed('v').mapError(() => 'new error'));
198
+ (0, vitest_1.expect)(index_1.Exit.isOk(exit)).toBe(true);
199
+ });
200
+ });
201
+ (0, vitest_1.describe)('Task#catchAll', () => {
202
+ (0, vitest_1.it)('recovers from an err', async () => {
203
+ const exit = await run(index_1.Task.fail('oops').catchAll(() => index_1.Task.succeed('recovered')));
204
+ (0, vitest_1.expect)(index_1.Exit.isOk(exit)).toBe(true);
205
+ if (index_1.Exit.isOk(exit))
206
+ (0, vitest_1.expect)(exit.value).toBe('recovered');
207
+ });
208
+ (0, vitest_1.it)('does not run the handler on ok', async () => {
209
+ let ran = false;
210
+ const exit = await run(index_1.Task.succeed(1).catchAll(() => {
211
+ ran = true;
212
+ return index_1.Task.succeed(2);
213
+ }));
214
+ (0, vitest_1.expect)(ran).toBe(false);
215
+ if (index_1.Exit.isOk(exit))
216
+ (0, vitest_1.expect)(exit.value).toBe(1);
217
+ });
218
+ (0, vitest_1.it)('passes die through unchanged', async () => {
219
+ const exit = await run(index_1.Task.die('fatal').catchAll(() => index_1.Task.succeed('recovered')));
220
+ (0, vitest_1.expect)(index_1.Exit.isDie(exit)).toBe(true);
221
+ });
222
+ });
223
+ (0, vitest_1.describe)('Task#catchWhen', () => {
224
+ (0, vitest_1.it)('handles only the matching error tag', async () => {
225
+ const errA = index_1.Task.fail({ _tag: 'A' });
226
+ const errB = index_1.Task.fail({ _tag: 'B' });
227
+ const exitA = await run(errA.catchWhen('_tag', 'A', () => index_1.Task.succeed('caught A')));
228
+ (0, vitest_1.expect)(index_1.Exit.isOk(exitA)).toBe(true);
229
+ if (index_1.Exit.isOk(exitA))
230
+ (0, vitest_1.expect)(exitA.value).toBe('caught A');
231
+ const exitB = await run(errB.catchWhen('_tag', 'A', () => index_1.Task.succeed('caught A')));
232
+ (0, vitest_1.expect)(index_1.Exit.isErr(exitB)).toBe(true);
233
+ if (index_1.Exit.isErr(exitB))
234
+ (0, vitest_1.expect)(exitB.error).toEqual({ _tag: 'B' });
235
+ });
236
+ });
237
+ (0, vitest_1.describe)('Task#filter', () => {
238
+ (0, vitest_1.it)('passes when the predicate holds', async () => {
239
+ const exit = await run(index_1.Task.succeed(10).filter((n) => n > 5, () => 'too small'));
240
+ (0, vitest_1.expect)(index_1.Exit.isOk(exit)).toBe(true);
241
+ });
242
+ (0, vitest_1.it)('fails when the predicate does not hold', async () => {
243
+ const exit = await run(index_1.Task.succeed(3).filter((n) => n > 5, (n) => `${n} is too small`));
244
+ (0, vitest_1.expect)(index_1.Exit.isErr(exit)).toBe(true);
245
+ if (index_1.Exit.isErr(exit))
246
+ (0, vitest_1.expect)(exit.error).toBe('3 is too small');
247
+ });
248
+ });
249
+ (0, vitest_1.describe)('Task#tapError', () => {
250
+ (0, vitest_1.it)('runs a side effect on err without changing it', async () => {
251
+ let seen;
252
+ const exit = await run(index_1.Task.fail('e').tapError((e) => { seen = e; }));
253
+ (0, vitest_1.expect)(seen).toBe('e');
254
+ (0, vitest_1.expect)(index_1.Exit.isErr(exit)).toBe(true);
255
+ if (index_1.Exit.isErr(exit))
256
+ (0, vitest_1.expect)(exit.error).toBe('e');
257
+ });
258
+ (0, vitest_1.it)('skips the side effect on ok', async () => {
259
+ let ran = false;
260
+ await run(index_1.Task.succeed(1).tapError(() => { ran = true; }));
261
+ (0, vitest_1.expect)(ran).toBe(false);
262
+ });
263
+ });
264
+ // ---------------------------------------------------------------------------
265
+ // Task.gen
266
+ // ---------------------------------------------------------------------------
267
+ (0, vitest_1.describe)('Task.gen', () => {
268
+ (0, vitest_1.it)('sequences successful tasks', async () => {
269
+ const exit = await run(index_1.Task.gen(function* () {
270
+ const a = yield* index_1.Task.succeed(1);
271
+ const b = yield* index_1.Task.succeed(2);
272
+ return a + b;
273
+ }));
274
+ (0, vitest_1.expect)(index_1.Exit.isOk(exit)).toBe(true);
275
+ if (index_1.Exit.isOk(exit))
276
+ (0, vitest_1.expect)(exit.value).toBe(3);
277
+ });
278
+ (0, vitest_1.it)('short-circuits on the first err', async () => {
279
+ let reached = false;
280
+ const exit = await run(index_1.Task.gen(function* () {
281
+ yield* index_1.Task.fail('first error');
282
+ reached = true;
283
+ yield* index_1.Task.succeed(1);
284
+ return 'done';
285
+ }));
286
+ (0, vitest_1.expect)(reached).toBe(false);
287
+ (0, vitest_1.expect)(index_1.Exit.isErr(exit)).toBe(true);
288
+ if (index_1.Exit.isErr(exit))
289
+ (0, vitest_1.expect)(exit.error).toBe('first error');
290
+ });
291
+ (0, vitest_1.it)('returns the final value', async () => {
292
+ const exit = await run(index_1.Task.gen(function* () {
293
+ const x = yield* index_1.Task.succeed(10);
294
+ return x * 3;
295
+ }));
296
+ (0, vitest_1.expect)(index_1.Exit.isOk(exit)).toBe(true);
297
+ if (index_1.Exit.isOk(exit))
298
+ (0, vitest_1.expect)(exit.value).toBe(30);
299
+ });
300
+ });
301
+ // ---------------------------------------------------------------------------
302
+ // Abort / fork
303
+ // ---------------------------------------------------------------------------
304
+ (0, vitest_1.describe)('Task#fork / abort', () => {
305
+ (0, vitest_1.it)('abort resolves to die', async () => {
306
+ const { exit, abort } = index_1.Task.never().fork();
307
+ abort();
308
+ const result = await exit;
309
+ (0, vitest_1.expect)(index_1.Exit.isDie(result)).toBe(true);
310
+ });
311
+ (0, vitest_1.it)('aborting an already-resolved task is a no-op', async () => {
312
+ const { exit, abort } = index_1.Task.succeed(1).fork();
313
+ const result = await exit;
314
+ abort();
315
+ (0, vitest_1.expect)(index_1.Exit.isOk(result)).toBe(true);
316
+ });
317
+ });
318
+ //# sourceMappingURL=index.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../src/task/index.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=paths.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.test.d.ts","sourceRoot":"","sources":["../../../../src/tools/firestore/utils/paths.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const paths_1 = require("./paths");
5
+ (0, vitest_1.describe)('segmentCount', () => {
6
+ (0, vitest_1.it)('counts single-segment paths', () => {
7
+ (0, vitest_1.expect)((0, paths_1.segmentCount)('users')).toBe(1);
8
+ });
9
+ (0, vitest_1.it)('counts multi-segment paths', () => {
10
+ (0, vitest_1.expect)((0, paths_1.segmentCount)('users/123/posts')).toBe(3);
11
+ (0, vitest_1.expect)((0, paths_1.segmentCount)('users/123')).toBe(2);
12
+ });
13
+ (0, vitest_1.it)('ignores leading and trailing slashes', () => {
14
+ (0, vitest_1.expect)((0, paths_1.segmentCount)('/users/')).toBe(1);
15
+ (0, vitest_1.expect)((0, paths_1.segmentCount)('/users/123/')).toBe(2);
16
+ });
17
+ (0, vitest_1.it)('returns 0 for an empty string', () => {
18
+ (0, vitest_1.expect)((0, paths_1.segmentCount)('')).toBe(0);
19
+ });
20
+ });
21
+ // ---------------------------------------------------------------------------
22
+ // collectionPathError
23
+ // ---------------------------------------------------------------------------
24
+ (0, vitest_1.describe)('collectionPathError', () => {
25
+ (0, vitest_1.it)('returns null for a valid single-segment collection path', () => {
26
+ (0, vitest_1.expect)((0, paths_1.collectionPathError)('users')).toBeNull();
27
+ });
28
+ (0, vitest_1.it)('returns null for a valid three-segment collection path', () => {
29
+ (0, vitest_1.expect)((0, paths_1.collectionPathError)('users/123/posts')).toBeNull();
30
+ });
31
+ (0, vitest_1.it)('returns null for a valid five-segment collection path', () => {
32
+ (0, vitest_1.expect)((0, paths_1.collectionPathError)('a/b/c/d/e')).toBeNull();
33
+ });
34
+ (0, vitest_1.it)('returns an error message for a two-segment (document) path', () => {
35
+ const msg = (0, paths_1.collectionPathError)('users/123');
36
+ (0, vitest_1.expect)(msg).toBeTypeOf('string');
37
+ (0, vitest_1.expect)(msg).toContain('2');
38
+ (0, vitest_1.expect)(msg).toContain('document path');
39
+ });
40
+ (0, vitest_1.it)('returns an error message for a four-segment path', () => {
41
+ const msg = (0, paths_1.collectionPathError)('stores/ABC/orders/456');
42
+ (0, vitest_1.expect)(msg).toBeTypeOf('string');
43
+ (0, vitest_1.expect)(msg).toContain('4');
44
+ });
45
+ });
46
+ // ---------------------------------------------------------------------------
47
+ // documentPathError
48
+ // ---------------------------------------------------------------------------
49
+ (0, vitest_1.describe)('documentPathError', () => {
50
+ (0, vitest_1.it)('returns null for a valid two-segment document path', () => {
51
+ (0, vitest_1.expect)((0, paths_1.documentPathError)('users/123')).toBeNull();
52
+ });
53
+ (0, vitest_1.it)('returns null for a valid four-segment document path', () => {
54
+ (0, vitest_1.expect)((0, paths_1.documentPathError)('stores/ABC/orders/456')).toBeNull();
55
+ });
56
+ (0, vitest_1.it)('returns an error message for a single-segment (collection) path', () => {
57
+ const msg = (0, paths_1.documentPathError)('users');
58
+ (0, vitest_1.expect)(msg).toBeTypeOf('string');
59
+ (0, vitest_1.expect)(msg).toContain('1');
60
+ (0, vitest_1.expect)(msg).toContain('collection path');
61
+ });
62
+ (0, vitest_1.it)('returns an error message for a three-segment path', () => {
63
+ const msg = (0, paths_1.documentPathError)('users/123/posts');
64
+ (0, vitest_1.expect)(msg).toBeTypeOf('string');
65
+ (0, vitest_1.expect)(msg).toContain('3');
66
+ });
67
+ });
68
+ //# sourceMappingURL=paths.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.test.js","sourceRoot":"","sources":["../../../../src/tools/firestore/utils/paths.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "firebase-mcp",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "description": "MCP server that exposes Firebase Firestore to AI agents (Cursor, Claude Desktop, etc.)",
5
5
  "main": "dist/cli/index.js",
6
6
  "bin": {
@@ -13,7 +13,10 @@
13
13
  "build": "tsc",
14
14
  "dev": "tsx src/cli/index.ts",
15
15
  "start": "node dist/cli/index.js",
16
- "prepublishOnly": "pnpm build"
16
+ "prepublishOnly": "pnpm build",
17
+ "test": "vitest run",
18
+ "test:watch": "vitest",
19
+ "test:coverage": "vitest run --coverage"
17
20
  },
18
21
  "keywords": [
19
22
  "mcp",