@fadlee/pocketbase-mcp 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 (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +123 -0
  3. package/build/src/config/cli.d.ts +9 -0
  4. package/build/src/config/cli.js +31 -0
  5. package/build/src/config/environment.d.ts +9 -0
  6. package/build/src/config/environment.js +13 -0
  7. package/build/src/config/index.d.ts +13 -0
  8. package/build/src/config/index.js +20 -0
  9. package/build/src/index.d.ts +2 -0
  10. package/build/src/index.js +21 -0
  11. package/build/src/server.d.ts +10 -0
  12. package/build/src/server.js +211 -0
  13. package/build/src/tools/handlers/analysis.d.ts +10 -0
  14. package/build/src/tools/handlers/analysis.js +127 -0
  15. package/build/src/tools/handlers/auth.d.ts +10 -0
  16. package/build/src/tools/handlers/auth.js +51 -0
  17. package/build/src/tools/handlers/collection.d.ts +22 -0
  18. package/build/src/tools/handlers/collection.js +82 -0
  19. package/build/src/tools/handlers/file.d.ts +5 -0
  20. package/build/src/tools/handlers/file.js +124 -0
  21. package/build/src/tools/handlers/generation.d.ts +10 -0
  22. package/build/src/tools/handlers/generation.js +201 -0
  23. package/build/src/tools/handlers/index.d.ts +10 -0
  24. package/build/src/tools/handlers/index.js +17 -0
  25. package/build/src/tools/handlers/migration.d.ts +18 -0
  26. package/build/src/tools/handlers/migration.js +219 -0
  27. package/build/src/tools/handlers/record.d.ts +18 -0
  28. package/build/src/tools/handlers/record.js +94 -0
  29. package/build/src/tools/index.d.ts +5 -0
  30. package/build/src/tools/index.js +7 -0
  31. package/build/src/tools/schemas/analysis.d.ts +56 -0
  32. package/build/src/tools/schemas/analysis.js +54 -0
  33. package/build/src/tools/schemas/auth.d.ts +59 -0
  34. package/build/src/tools/schemas/auth.js +59 -0
  35. package/build/src/tools/schemas/collection.d.ts +192 -0
  36. package/build/src/tools/schemas/collection.js +194 -0
  37. package/build/src/tools/schemas/file.d.ts +70 -0
  38. package/build/src/tools/schemas/file.js +70 -0
  39. package/build/src/tools/schemas/generation.d.ts +49 -0
  40. package/build/src/tools/schemas/generation.js +49 -0
  41. package/build/src/tools/schemas/index.d.ts +10 -0
  42. package/build/src/tools/schemas/index.js +17 -0
  43. package/build/src/tools/schemas/migration.d.ts +133 -0
  44. package/build/src/tools/schemas/migration.js +146 -0
  45. package/build/src/tools/schemas/record.d.ts +103 -0
  46. package/build/src/tools/schemas/record.js +103 -0
  47. package/build/src/types/index.d.ts +188 -0
  48. package/build/src/types/index.js +1 -0
  49. package/build/src/utils/errors.d.ts +17 -0
  50. package/build/src/utils/errors.js +35 -0
  51. package/build/src/utils/response.d.ts +23 -0
  52. package/build/src/utils/response.js +62 -0
  53. package/build/src/utils/typescript.d.ts +24 -0
  54. package/build/src/utils/typescript.js +130 -0
  55. package/package.json +57 -0
@@ -0,0 +1,219 @@
1
+ import { handlePocketBaseError } from "../../utils/errors.js";
2
+ import { createJsonResponse, createTextResponse } from "../../utils/response.js";
3
+ import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
4
+ /**
5
+ * Migrate collection schema with data preservation
6
+ */
7
+ export function createMigrateCollectionHandler(pb) {
8
+ return async (args) => {
9
+ try {
10
+ const { collection, fields, dataTransforms = {}, name, ...rules } = args;
11
+ // Prepare update data
12
+ const updateData = {
13
+ fields,
14
+ ...rules,
15
+ };
16
+ if (name)
17
+ updateData.name = name;
18
+ // Update collection schema
19
+ const updatedCollection = await pb.collections.update(collection, updateData);
20
+ // If there are data transforms, apply them
21
+ if (Object.keys(dataTransforms).length > 0) {
22
+ const records = await pb.collection(collection).getFullList();
23
+ for (const record of records) {
24
+ const updates = {};
25
+ let hasUpdates = false;
26
+ for (const [oldField, newField] of Object.entries(dataTransforms)) {
27
+ if (record[oldField] !== undefined) {
28
+ updates[newField] = record[oldField];
29
+ hasUpdates = true;
30
+ }
31
+ }
32
+ if (hasUpdates) {
33
+ await pb.collection(collection).update(record.id, updates);
34
+ }
35
+ }
36
+ }
37
+ return createJsonResponse({
38
+ success: true,
39
+ collection: updatedCollection,
40
+ message: `Collection '${collection}' migrated successfully`,
41
+ });
42
+ }
43
+ catch (error) {
44
+ throw handlePocketBaseError("migrate collection", error);
45
+ }
46
+ };
47
+ }
48
+ /**
49
+ * Create a backup of the PocketBase database
50
+ */
51
+ export function createBackupDatabaseHandler(pb) {
52
+ return async (args = {}) => {
53
+ try {
54
+ const format = args.format || "json";
55
+ // Get all collections
56
+ const collections = await pb.collections.getFullList();
57
+ const backup = {
58
+ timestamp: new Date().toISOString(),
59
+ collections: {},
60
+ };
61
+ // Export each collection
62
+ for (const collection of collections) {
63
+ const records = await pb.collection(collection.name).getFullList();
64
+ backup.collections[collection.name] = {
65
+ schema: collection,
66
+ records,
67
+ };
68
+ }
69
+ if (format === "csv") {
70
+ // For CSV, we'll export each collection separately
71
+ const csvData = [];
72
+ for (const [collectionName, data] of Object.entries(backup.collections)) {
73
+ const collectionData = data;
74
+ if (collectionData.records.length > 0) {
75
+ csvData.push(`\n--- Collection: ${collectionName} ---`);
76
+ // Format records as CSV
77
+ const records = collectionData.records;
78
+ if (records.length > 0) {
79
+ const headers = Object.keys(records[0]);
80
+ csvData.push(headers.join(","));
81
+ records.forEach((record) => {
82
+ const values = headers.map((header) => {
83
+ const value = record[header];
84
+ return typeof value === "string" && value.includes(",")
85
+ ? `"${value.replace(/"/g, '""')}"`
86
+ : String(value || "");
87
+ });
88
+ csvData.push(values.join(","));
89
+ });
90
+ }
91
+ }
92
+ }
93
+ return createTextResponse(csvData.join("\n"));
94
+ }
95
+ return createJsonResponse(backup);
96
+ }
97
+ catch (error) {
98
+ throw handlePocketBaseError("backup database", error);
99
+ }
100
+ };
101
+ }
102
+ /**
103
+ * Import data into a collection
104
+ */
105
+ export function createImportDataHandler(pb) {
106
+ return async (args) => {
107
+ try {
108
+ const { collection, data, mode = "create" } = args;
109
+ const results = {
110
+ created: 0,
111
+ updated: 0,
112
+ errors: [],
113
+ };
114
+ for (const item of data) {
115
+ try {
116
+ switch (mode) {
117
+ case "create":
118
+ await pb.collection(collection).create(item);
119
+ results.created++;
120
+ break;
121
+ case "update":
122
+ if (!item.id) {
123
+ results.errors.push("Update mode requires 'id' field in each record");
124
+ continue;
125
+ }
126
+ await pb.collection(collection).update(item.id, item);
127
+ results.updated++;
128
+ break;
129
+ case "upsert":
130
+ if (item.id) {
131
+ try {
132
+ await pb.collection(collection).update(item.id, item);
133
+ results.updated++;
134
+ }
135
+ catch {
136
+ await pb.collection(collection).create(item);
137
+ results.created++;
138
+ }
139
+ }
140
+ else {
141
+ await pb.collection(collection).create(item);
142
+ results.created++;
143
+ }
144
+ break;
145
+ default:
146
+ throw new McpError(ErrorCode.InvalidParams, `Unsupported import mode: ${mode}`);
147
+ }
148
+ }
149
+ catch (error) {
150
+ results.errors.push(`Failed to import record: ${error.message}`);
151
+ }
152
+ }
153
+ return createJsonResponse({
154
+ success: true,
155
+ results,
156
+ message: `Import completed: ${results.created} created, ${results.updated} updated, ${results.errors.length} errors`,
157
+ });
158
+ }
159
+ catch (error) {
160
+ throw handlePocketBaseError("import data", error);
161
+ }
162
+ };
163
+ }
164
+ /**
165
+ * Manage collection indexes
166
+ */
167
+ export function createManageIndexesHandler(pb) {
168
+ return async (args) => {
169
+ try {
170
+ const { collection, action, index } = args;
171
+ switch (action) {
172
+ case "list": {
173
+ const collectionInfo = await pb.collections.getOne(collection);
174
+ return createJsonResponse({
175
+ collection,
176
+ indexes: collectionInfo.indexes || [],
177
+ });
178
+ }
179
+ case "create": {
180
+ if (!index) {
181
+ throw new McpError(ErrorCode.InvalidParams, "Index configuration required for create action");
182
+ }
183
+ const currentCollection = await pb.collections.getOne(collection);
184
+ const currentIndexes = currentCollection.indexes || [];
185
+ // Add new index
186
+ const newIndexes = [...currentIndexes, index];
187
+ await pb.collections.update(collection, {
188
+ indexes: newIndexes,
189
+ });
190
+ return createJsonResponse({
191
+ success: true,
192
+ message: `Index '${index.name}' created successfully`,
193
+ indexes: newIndexes,
194
+ });
195
+ }
196
+ case "delete": {
197
+ if (!index?.name) {
198
+ throw new McpError(ErrorCode.InvalidParams, "Index name required for delete action");
199
+ }
200
+ const collectionToUpdate = await pb.collections.getOne(collection);
201
+ const filteredIndexes = (collectionToUpdate.indexes || []).filter((idx) => idx.name !== index.name);
202
+ await pb.collections.update(collection, {
203
+ indexes: filteredIndexes,
204
+ });
205
+ return createJsonResponse({
206
+ success: true,
207
+ message: `Index '${index.name}' deleted successfully`,
208
+ indexes: filteredIndexes,
209
+ });
210
+ }
211
+ default:
212
+ throw new McpError(ErrorCode.InvalidParams, `Unsupported index action: ${action}`);
213
+ }
214
+ }
215
+ catch (error) {
216
+ throw handlePocketBaseError("manage indexes", error);
217
+ }
218
+ };
219
+ }
@@ -0,0 +1,18 @@
1
+ import type PocketBase from "pocketbase";
2
+ import type { ToolHandler } from "../../types/index.js";
3
+ /**
4
+ * Create a new record in a collection
5
+ */
6
+ export declare function createCreateRecordHandler(pb: PocketBase): ToolHandler;
7
+ /**
8
+ * List records from a collection with optional filters
9
+ */
10
+ export declare function createListRecordsHandler(pb: PocketBase): ToolHandler;
11
+ /**
12
+ * Update an existing record
13
+ */
14
+ export declare function createUpdateRecordHandler(pb: PocketBase): ToolHandler;
15
+ /**
16
+ * Delete a record
17
+ */
18
+ export declare function createDeleteRecordHandler(pb: PocketBase): ToolHandler;
@@ -0,0 +1,94 @@
1
+ import { handlePocketBaseError } from "../../utils/errors.js";
2
+ import { createJsonResponse } from "../../utils/response.js";
3
+ /**
4
+ * Create a new record in a collection
5
+ */
6
+ export function createCreateRecordHandler(pb) {
7
+ return async (args) => {
8
+ try {
9
+ const options = {};
10
+ // Add optional parameters
11
+ if (args.expand)
12
+ options.expand = args.expand;
13
+ if (args.fields)
14
+ options.fields = args.fields;
15
+ const result = await pb
16
+ .collection(args.collection)
17
+ .create(args.data, options);
18
+ return createJsonResponse(result);
19
+ }
20
+ catch (error) {
21
+ throw handlePocketBaseError("create record", error);
22
+ }
23
+ };
24
+ }
25
+ /**
26
+ * List records from a collection with optional filters
27
+ */
28
+ export function createListRecordsHandler(pb) {
29
+ return async (args) => {
30
+ try {
31
+ const options = {};
32
+ // Add optional parameters
33
+ if (args.filter)
34
+ options.filter = args.filter;
35
+ if (args.sort)
36
+ options.sort = args.sort;
37
+ if (args.expand)
38
+ options.expand = args.expand;
39
+ if (args.fields)
40
+ options.fields = args.fields;
41
+ if (args.skipTotal !== undefined)
42
+ options.skipTotal = args.skipTotal;
43
+ // Set pagination
44
+ const page = args.page || 1;
45
+ const perPage = args.perPage || 50;
46
+ const result = await pb
47
+ .collection(args.collection)
48
+ .getList(page, perPage, options);
49
+ return createJsonResponse(result);
50
+ }
51
+ catch (error) {
52
+ throw handlePocketBaseError("list records", error);
53
+ }
54
+ };
55
+ }
56
+ /**
57
+ * Update an existing record
58
+ */
59
+ export function createUpdateRecordHandler(pb) {
60
+ return async (args) => {
61
+ try {
62
+ const options = {};
63
+ // Add optional parameters
64
+ if (args.expand)
65
+ options.expand = args.expand;
66
+ if (args.fields)
67
+ options.fields = args.fields;
68
+ const result = await pb
69
+ .collection(args.collection)
70
+ .update(args.id, args.data, options);
71
+ return createJsonResponse(result);
72
+ }
73
+ catch (error) {
74
+ throw handlePocketBaseError("update record", error);
75
+ }
76
+ };
77
+ }
78
+ /**
79
+ * Delete a record
80
+ */
81
+ export function createDeleteRecordHandler(pb) {
82
+ return async (args) => {
83
+ try {
84
+ await pb.collection(args.collection).delete(args.id);
85
+ return createJsonResponse({
86
+ success: true,
87
+ message: `Record '${args.id}' deleted successfully from collection '${args.collection}'`
88
+ });
89
+ }
90
+ catch (error) {
91
+ throw handlePocketBaseError("delete record", error);
92
+ }
93
+ };
94
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Tools module - exports schemas and handlers
3
+ */
4
+ export * from "./schemas/index.js";
5
+ export * from "./handlers/index.js";
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Tools module - exports schemas and handlers
3
+ */
4
+ // Export all schemas
5
+ export * from "./schemas/index.js";
6
+ // Export all handlers
7
+ export * from "./handlers/index.js";
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Tool input schemas for analysis-related operations
3
+ */
4
+ export declare const analyzeCollectionDataSchema: {
5
+ type: string;
6
+ properties: {
7
+ collection: {
8
+ type: string;
9
+ description: string;
10
+ };
11
+ options: {
12
+ type: string;
13
+ description: string;
14
+ properties: {
15
+ sampleSize: {
16
+ type: string;
17
+ description: string;
18
+ };
19
+ fields: {
20
+ type: string;
21
+ items: {
22
+ type: string;
23
+ };
24
+ description: string;
25
+ };
26
+ };
27
+ };
28
+ };
29
+ required: string[];
30
+ };
31
+ export declare const queryCollectionSchema: {
32
+ type: string;
33
+ properties: {
34
+ collection: {
35
+ type: string;
36
+ description: string;
37
+ };
38
+ filter: {
39
+ type: string;
40
+ description: string;
41
+ };
42
+ sort: {
43
+ type: string;
44
+ description: string;
45
+ };
46
+ aggregate: {
47
+ type: string;
48
+ description: string;
49
+ };
50
+ expand: {
51
+ type: string;
52
+ description: string;
53
+ };
54
+ };
55
+ required: string[];
56
+ };
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Tool input schemas for analysis-related operations
3
+ */
4
+ export const analyzeCollectionDataSchema = {
5
+ type: "object",
6
+ properties: {
7
+ collection: {
8
+ type: "string",
9
+ description: "Collection name to analyze",
10
+ },
11
+ options: {
12
+ type: "object",
13
+ description: "Analysis options",
14
+ properties: {
15
+ sampleSize: {
16
+ type: "number",
17
+ description: "Number of records to sample for analysis (default: 100)",
18
+ },
19
+ fields: {
20
+ type: "array",
21
+ items: { type: "string" },
22
+ description: "Specific fields to analyze (if not provided, all fields will be analyzed)",
23
+ },
24
+ },
25
+ },
26
+ },
27
+ required: ["collection"],
28
+ };
29
+ export const queryCollectionSchema = {
30
+ type: "object",
31
+ properties: {
32
+ collection: {
33
+ type: "string",
34
+ description: "Collection name",
35
+ },
36
+ filter: {
37
+ type: "string",
38
+ description: "Filter expression",
39
+ },
40
+ sort: {
41
+ type: "string",
42
+ description: "Sort expression",
43
+ },
44
+ aggregate: {
45
+ type: "object",
46
+ description: "Aggregation settings",
47
+ },
48
+ expand: {
49
+ type: "string",
50
+ description: "Relations to expand",
51
+ },
52
+ },
53
+ required: ["collection"],
54
+ };
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Tool input schemas for authentication-related operations
3
+ */
4
+ export declare const authenticateUserSchema: {
5
+ type: string;
6
+ properties: {
7
+ collection: {
8
+ type: string;
9
+ description: string;
10
+ };
11
+ email: {
12
+ type: string;
13
+ description: string;
14
+ };
15
+ password: {
16
+ type: string;
17
+ description: string;
18
+ };
19
+ autoRefreshThreshold: {
20
+ type: string;
21
+ description: string;
22
+ };
23
+ };
24
+ required: string[];
25
+ };
26
+ export declare const createUserSchema: {
27
+ type: string;
28
+ properties: {
29
+ collection: {
30
+ type: string;
31
+ description: string;
32
+ };
33
+ email: {
34
+ type: string;
35
+ description: string;
36
+ };
37
+ password: {
38
+ type: string;
39
+ description: string;
40
+ };
41
+ passwordConfirm: {
42
+ type: string;
43
+ description: string;
44
+ };
45
+ verified: {
46
+ type: string;
47
+ description: string;
48
+ };
49
+ emailVisibility: {
50
+ type: string;
51
+ description: string;
52
+ };
53
+ additionalData: {
54
+ type: string;
55
+ description: string;
56
+ };
57
+ };
58
+ required: string[];
59
+ };
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Tool input schemas for authentication-related operations
3
+ */
4
+ export const authenticateUserSchema = {
5
+ type: "object",
6
+ properties: {
7
+ collection: {
8
+ type: "string",
9
+ description: "Auth collection name (default: 'users')",
10
+ },
11
+ email: {
12
+ type: "string",
13
+ description: "User email or identity field value",
14
+ },
15
+ password: {
16
+ type: "string",
17
+ description: "User password",
18
+ },
19
+ autoRefreshThreshold: {
20
+ type: "number",
21
+ description: "Time in seconds that will trigger token auto refresh before its expiration (default: 30 minutes)",
22
+ },
23
+ },
24
+ required: ["email", "password"],
25
+ };
26
+ export const createUserSchema = {
27
+ type: "object",
28
+ properties: {
29
+ collection: {
30
+ type: "string",
31
+ description: "Auth collection name (default: 'users')",
32
+ },
33
+ email: {
34
+ type: "string",
35
+ description: "User email",
36
+ },
37
+ password: {
38
+ type: "string",
39
+ description: "User password",
40
+ },
41
+ passwordConfirm: {
42
+ type: "string",
43
+ description: "Password confirmation (must match password)",
44
+ },
45
+ verified: {
46
+ type: "boolean",
47
+ description: "Whether the user is verified (default: false)",
48
+ },
49
+ emailVisibility: {
50
+ type: "boolean",
51
+ description: "Whether the user email is publicly visible (default: false)",
52
+ },
53
+ additionalData: {
54
+ type: "object",
55
+ description: "Additional user data fields specific to your auth collection",
56
+ },
57
+ },
58
+ required: ["email", "password", "passwordConfirm"],
59
+ };