@influxdata/influxdb3-mcp-server 1.3.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 (40) hide show
  1. package/CHANGELOG.md +194 -0
  2. package/Dockerfile +22 -0
  3. package/LICENSE +6 -0
  4. package/LICENSE-APACHE.txt +201 -0
  5. package/LICENSE-MIT.txt +25 -0
  6. package/README.md +318 -0
  7. package/build/config.js +85 -0
  8. package/build/helpers/enums/influx-product-types.enum.js +8 -0
  9. package/build/index.js +33 -0
  10. package/build/prompts/index.js +98 -0
  11. package/build/resources/index.js +223 -0
  12. package/build/server/index.js +104 -0
  13. package/build/services/base-connection.service.js +318 -0
  14. package/build/services/cloud-token-management.service.js +179 -0
  15. package/build/services/context-file.service.js +97 -0
  16. package/build/services/database-management.service.js +549 -0
  17. package/build/services/help.service.js +241 -0
  18. package/build/services/http-client.service.js +109 -0
  19. package/build/services/influxdb-master.service.js +117 -0
  20. package/build/services/query.service.js +499 -0
  21. package/build/services/serverless-schema-management.service.js +266 -0
  22. package/build/services/token-management.service.js +215 -0
  23. package/build/services/write.service.js +153 -0
  24. package/build/tools/categories/cloud-token.tools.js +321 -0
  25. package/build/tools/categories/database.tools.js +299 -0
  26. package/build/tools/categories/health.tools.js +75 -0
  27. package/build/tools/categories/help.tools.js +104 -0
  28. package/build/tools/categories/query.tools.js +180 -0
  29. package/build/tools/categories/schema.tools.js +308 -0
  30. package/build/tools/categories/token.tools.js +378 -0
  31. package/build/tools/categories/write.tools.js +104 -0
  32. package/build/tools/index.js +27 -0
  33. package/env.example +17 -0
  34. package/example-cloud-dedicated.mcp.json +15 -0
  35. package/example-cloud-serverless.mcp.json +13 -0
  36. package/example-clustered.mcp.json +14 -0
  37. package/example-docker.mcp.json +25 -0
  38. package/example-local.mcp.json +13 -0
  39. package/example-npx.mcp.json +13 -0
  40. package/package.json +78 -0
@@ -0,0 +1,321 @@
1
+ /**
2
+ * Cloud Token Management Tools (Cloud-Dedicated/Clustered)
3
+ */
4
+ import { z } from "zod";
5
+ export function createCloudTokenTools(influxService) {
6
+ return [
7
+ {
8
+ name: "cloud_list_database_tokens",
9
+ description: "List all database tokens for InfluxDB Cloud-Dedicated/Clustered cluster. Returns token information including permissions and creation dates.",
10
+ inputSchema: {
11
+ type: "object",
12
+ properties: {},
13
+ additionalProperties: false,
14
+ },
15
+ zodSchema: z.object({}),
16
+ handler: async () => {
17
+ try {
18
+ const cloudTokenService = influxService.getCloudTokenManagementService();
19
+ const tokens = await cloudTokenService.listTokens();
20
+ const tokenCount = tokens.length;
21
+ const tokenList = tokens
22
+ .map((token) => `• ${token.description} (ID: ${token.id})\n Permissions: ${token.permissions.length > 0 ? token.permissions.map((p) => `${p.action}:${p.resource}`).join(", ") : "No access"}\n Created: ${token.createdAt}`)
23
+ .join("\n");
24
+ return {
25
+ content: [
26
+ {
27
+ type: "text",
28
+ text: `Found ${tokenCount} database token${tokenCount !== 1 ? "s" : ""} in Cloud-Dedicated/Clustered cluster:\n\n${tokenList || "None"}\n\nFull details:\n${JSON.stringify(tokens, null, 2)}`,
29
+ },
30
+ ],
31
+ };
32
+ }
33
+ catch (error) {
34
+ return {
35
+ content: [
36
+ {
37
+ type: "text",
38
+ text: `Error: ${error.message}`,
39
+ },
40
+ ],
41
+ isError: true,
42
+ };
43
+ }
44
+ },
45
+ },
46
+ {
47
+ name: "cloud_get_database_token",
48
+ description: "Get details of a specific database token by ID for InfluxDB Cloud-Dedicated/Clustered cluster.",
49
+ inputSchema: {
50
+ type: "object",
51
+ properties: {
52
+ token_id: {
53
+ type: "string",
54
+ description: "The ID of the token to retrieve",
55
+ },
56
+ },
57
+ required: ["token_id"],
58
+ additionalProperties: false,
59
+ },
60
+ zodSchema: z.object({
61
+ token_id: z.string().describe("The ID of the token to retrieve"),
62
+ }),
63
+ handler: async (args) => {
64
+ try {
65
+ const cloudTokenService = influxService.getCloudTokenManagementService();
66
+ const token = await cloudTokenService.getToken(args.token_id);
67
+ const permissionsList = token.permissions.length > 0
68
+ ? token.permissions
69
+ .map((p) => `${p.action}:${p.resource}`)
70
+ .join(", ")
71
+ : "No access";
72
+ return {
73
+ content: [
74
+ {
75
+ type: "text",
76
+ text: `Database Token Details:\n\nDescription: ${token.description}\nID: ${token.id}\nPermissions: ${permissionsList}\nCreated: ${token.createdAt}\nAccount ID: ${token.accountId}\nCluster ID: ${token.clusterId}\n\nFull details:\n${JSON.stringify(token, null, 2)}`,
77
+ },
78
+ ],
79
+ };
80
+ }
81
+ catch (error) {
82
+ return {
83
+ content: [
84
+ {
85
+ type: "text",
86
+ text: `Error: ${error.message}`,
87
+ },
88
+ ],
89
+ isError: true,
90
+ };
91
+ }
92
+ },
93
+ },
94
+ {
95
+ name: "cloud_create_database_token",
96
+ description: 'Create a new database token for InfluxDB Cloud-Dedicated/Clustered cluster. Specify exact permissions per database or create a no-access token.\n\nPermissions format: [{"database": "db_name", "action": "read|write"}, ...]\nExamples:\n• No access: omit permissions field or use []\n• Read-only on \'analytics\': [{"database": "analytics", "action": "read"}]\n• Mixed permissions: [{"database": "logs", "action": "read"}, {"database": "metrics", "action": "write"}]\n• Full access: [{"database": "*", "action": "read"}, {"database": "*", "action": "write"}]',
97
+ inputSchema: {
98
+ type: "object",
99
+ properties: {
100
+ description: {
101
+ type: "string",
102
+ description: "Description/name for the token",
103
+ },
104
+ permissions: {
105
+ type: "array",
106
+ items: {
107
+ type: "object",
108
+ properties: {
109
+ database: {
110
+ type: "string",
111
+ description: "Database name or '*' for all databases",
112
+ },
113
+ action: {
114
+ type: "string",
115
+ enum: ["read", "write"],
116
+ description: "Permission level for this database",
117
+ },
118
+ },
119
+ required: ["database", "action"],
120
+ additionalProperties: false,
121
+ },
122
+ description: "Array of permission objects. Each object specifies database and action. Leave empty array [] for no-access token.",
123
+ },
124
+ },
125
+ required: ["description"],
126
+ additionalProperties: false,
127
+ },
128
+ zodSchema: z.object({
129
+ description: z.string().describe("Description/name for the token"),
130
+ permissions: z
131
+ .array(z.object({
132
+ database: z
133
+ .string()
134
+ .describe("Database name or '*' for all databases"),
135
+ action: z
136
+ .enum(["read", "write"])
137
+ .describe("Permission level for this database"),
138
+ }))
139
+ .optional()
140
+ .describe("Array of permission objects. Omit or use empty array for no-access token"),
141
+ }),
142
+ handler: async (args) => {
143
+ try {
144
+ const cloudTokenService = influxService.getCloudTokenManagementService();
145
+ const permissions = (args.permissions || []).map((p) => ({
146
+ action: p.action,
147
+ resource: p.database,
148
+ }));
149
+ const result = await cloudTokenService.createToken({
150
+ description: args.description,
151
+ permissions,
152
+ });
153
+ const permissionsList = result.permissions.length > 0
154
+ ? result.permissions
155
+ .map((p) => `${p.action}:${p.resource}`)
156
+ .join(", ")
157
+ : "No access";
158
+ return {
159
+ content: [
160
+ {
161
+ type: "text",
162
+ text: `Database token created successfully!\n\nDescription: ${result.description}\nToken ID: ${result.id}\nPermissions: ${permissionsList}\nAccess Token: ${result.accessToken}\n\n⚠️ Store this access token securely - it won't be shown again!`,
163
+ },
164
+ ],
165
+ };
166
+ }
167
+ catch (error) {
168
+ return {
169
+ content: [
170
+ {
171
+ type: "text",
172
+ text: `Error: ${error.message}`,
173
+ },
174
+ ],
175
+ isError: true,
176
+ };
177
+ }
178
+ },
179
+ },
180
+ {
181
+ name: "cloud_update_database_token",
182
+ description: 'Update an existing database token for InfluxDB Cloud-Dedicated/Clustered cluster. Can update description and/or permissions with precise control.\n\nPermissions format: [{"database": "db_name", "action": "read|write"}, ...]\nNote: Permissions completely replace existing ones - include all desired permissions.\nExamples:\n• No access: use []\n• Read-only on \'analytics\': [{"database": "analytics", "action": "read"}]\n• Mixed permissions: [{"database": "logs", "action": "read"}, {"database": "metrics", "action": "write"}]\n• Full access: [{"database": "*", "action": "read"}, {"database": "*", "action": "write"}]',
183
+ inputSchema: {
184
+ type: "object",
185
+ properties: {
186
+ token_id: {
187
+ type: "string",
188
+ description: "The ID of the token to update",
189
+ },
190
+ description: {
191
+ type: "string",
192
+ description: "New description for the token (optional)",
193
+ },
194
+ permissions: {
195
+ type: "array",
196
+ items: {
197
+ type: "object",
198
+ properties: {
199
+ database: {
200
+ type: "string",
201
+ description: "Database name or '*' for all databases",
202
+ },
203
+ action: {
204
+ type: "string",
205
+ enum: ["read", "write"],
206
+ description: "Permission level for this database",
207
+ },
208
+ },
209
+ required: ["database", "action"],
210
+ additionalProperties: false,
211
+ },
212
+ description: "Array of permission objects. Each object specifies database and action. Use empty array [] for no-access token.",
213
+ },
214
+ },
215
+ required: ["token_id"],
216
+ additionalProperties: false,
217
+ },
218
+ zodSchema: z.object({
219
+ token_id: z.string().describe("The ID of the token to update"),
220
+ description: z
221
+ .string()
222
+ .optional()
223
+ .describe("New description for the token"),
224
+ permissions: z
225
+ .array(z.object({
226
+ database: z
227
+ .string()
228
+ .describe("Database name or '*' for all databases"),
229
+ action: z
230
+ .enum(["read", "write"])
231
+ .describe("Permission level for this database"),
232
+ }))
233
+ .optional()
234
+ .describe("Array of permission objects. Use empty array for no-access token"),
235
+ }),
236
+ handler: async (args) => {
237
+ try {
238
+ const cloudTokenService = influxService.getCloudTokenManagementService();
239
+ const updateRequest = {};
240
+ if (args.description !== undefined) {
241
+ updateRequest.description = args.description;
242
+ }
243
+ if (args.permissions !== undefined) {
244
+ updateRequest.permissions = args.permissions.map((p) => ({
245
+ action: p.action,
246
+ resource: p.database,
247
+ }));
248
+ }
249
+ const result = await cloudTokenService.updateToken(args.token_id, updateRequest);
250
+ const permissionsList = result.permissions.length > 0
251
+ ? result.permissions
252
+ .map((p) => `${p.action}:${p.resource}`)
253
+ .join(", ")
254
+ : "No access";
255
+ return {
256
+ content: [
257
+ {
258
+ type: "text",
259
+ text: `Database token updated successfully!\n\nDescription: ${result.description}\nToken ID: ${result.id}\nPermissions: ${permissionsList}\nCreated: ${result.createdAt}`,
260
+ },
261
+ ],
262
+ };
263
+ }
264
+ catch (error) {
265
+ return {
266
+ content: [
267
+ {
268
+ type: "text",
269
+ text: `Error: ${error.message}`,
270
+ },
271
+ ],
272
+ isError: true,
273
+ };
274
+ }
275
+ },
276
+ },
277
+ {
278
+ name: "cloud_delete_database_token",
279
+ description: "Delete a database token from InfluxDB Cloud-Dedicated/Clustered cluster. This action cannot be undone.",
280
+ inputSchema: {
281
+ type: "object",
282
+ properties: {
283
+ token_id: {
284
+ type: "string",
285
+ description: "The ID of the token to delete",
286
+ },
287
+ },
288
+ required: ["token_id"],
289
+ additionalProperties: false,
290
+ },
291
+ zodSchema: z.object({
292
+ token_id: z.string().describe("The ID of the token to delete"),
293
+ }),
294
+ handler: async (args) => {
295
+ try {
296
+ const cloudTokenService = influxService.getCloudTokenManagementService();
297
+ await cloudTokenService.deleteToken(args.token_id);
298
+ return {
299
+ content: [
300
+ {
301
+ type: "text",
302
+ text: `Database token '${args.token_id}' deleted successfully.`,
303
+ },
304
+ ],
305
+ };
306
+ }
307
+ catch (error) {
308
+ return {
309
+ content: [
310
+ {
311
+ type: "text",
312
+ text: `Error: ${error.message}`,
313
+ },
314
+ ],
315
+ isError: true,
316
+ };
317
+ }
318
+ },
319
+ },
320
+ ];
321
+ }
@@ -0,0 +1,299 @@
1
+ /**
2
+ * Database Management Tools
3
+ */
4
+ import { z } from "zod";
5
+ export function createDatabaseTools(influxService) {
6
+ return [
7
+ {
8
+ name: "create_database",
9
+ description: "Create a new database in InfluxDB. Database names must follow InfluxDB naming rules: alphanumeric characters, dashes (-), underscores (_), and forward slashes (/) are allowed. Must start with a letter or number. Maximum 64 characters. For Cloud Dedicated/Clustered: maxTables, maxColumnsPerTable, retentionPeriod. For Cloud Serverless: description, retentionPeriod.",
10
+ inputSchema: {
11
+ type: "object",
12
+ properties: {
13
+ name: {
14
+ type: "string",
15
+ description: "Name of the database to create (alphanumeric, -, _, / allowed; max 64 chars; must start with letter/number)",
16
+ pattern: "^[a-zA-Z0-9][a-zA-Z0-9\\-_/]*$",
17
+ maxLength: 64,
18
+ },
19
+ description: {
20
+ type: "string",
21
+ description: "Description for the bucket/database (Cloud Serverless only)",
22
+ },
23
+ maxTables: {
24
+ type: "number",
25
+ description: "Maximum number of tables (Cloud Dedicated/Clustered only, default: 500)",
26
+ minimum: 1,
27
+ },
28
+ maxColumnsPerTable: {
29
+ type: "number",
30
+ description: "Maximum columns per table (Cloud Dedicated/Clustered only, default: 200)",
31
+ minimum: 1,
32
+ },
33
+ retentionPeriod: {
34
+ type: "number",
35
+ description: "Retention period in nanoseconds (Cloud Dedicated/Clustered: default 0 = no expiration, Cloud Serverless: default 30 days)",
36
+ minimum: 0,
37
+ },
38
+ },
39
+ required: ["name"],
40
+ additionalProperties: false,
41
+ },
42
+ zodSchema: z.object({
43
+ name: z
44
+ .string()
45
+ .min(1, "Database name cannot be empty")
46
+ .max(64, "Database name cannot exceed 64 characters")
47
+ .regex(/^[a-zA-Z0-9]/, "Database name must start with a letter or number")
48
+ .regex(/^[a-zA-Z0-9\-_/]+$/, "Database name can only contain alphanumeric characters, dashes (-), underscores (_), and forward slashes (/)")
49
+ .describe("Name of the database to create"),
50
+ description: z
51
+ .string()
52
+ .optional()
53
+ .describe("Description for the bucket/database (Cloud Serverless only)"),
54
+ maxTables: z
55
+ .number()
56
+ .min(1)
57
+ .optional()
58
+ .describe("Maximum number of tables (Cloud Dedicated/Clustered only)"),
59
+ maxColumnsPerTable: z
60
+ .number()
61
+ .min(1)
62
+ .optional()
63
+ .describe("Maximum columns per table (Cloud Dedicated/Clustered only)"),
64
+ retentionPeriod: z
65
+ .number()
66
+ .min(0)
67
+ .optional()
68
+ .describe("Retention period in nanoseconds"),
69
+ }),
70
+ handler: async (args) => {
71
+ try {
72
+ const config = args.maxTables !== undefined ||
73
+ args.maxColumnsPerTable !== undefined ||
74
+ args.retentionPeriod !== undefined ||
75
+ args.description !== undefined
76
+ ? {
77
+ name: args.name,
78
+ ...(args.maxTables !== undefined && {
79
+ maxTables: args.maxTables,
80
+ }),
81
+ ...(args.maxColumnsPerTable !== undefined && {
82
+ maxColumnsPerTable: args.maxColumnsPerTable,
83
+ }),
84
+ ...(args.description !== undefined && {
85
+ description: args.description,
86
+ }),
87
+ ...(args.retentionPeriod !== undefined && {
88
+ retentionPeriod: args.retentionPeriod,
89
+ }),
90
+ }
91
+ : undefined;
92
+ await influxService.database.createDatabase(args.name, config);
93
+ return {
94
+ content: [
95
+ {
96
+ type: "text",
97
+ text: `Database '${args.name}' created successfully`,
98
+ },
99
+ ],
100
+ };
101
+ }
102
+ catch (error) {
103
+ return {
104
+ content: [
105
+ {
106
+ type: "text",
107
+ text: `Error: ${error.message}`,
108
+ },
109
+ ],
110
+ isError: true,
111
+ };
112
+ }
113
+ },
114
+ },
115
+ {
116
+ name: "update_database",
117
+ description: "Update database configuration for InfluxDB Cloud Dedicated/Clustered clusters and Cloud Serverless buckets. For Cloud Dedicated/Clustered: modify maxTables, maxColumnsPerTable, and retentionPeriod. For Cloud Serverless: modify bucket name, description, and retentionPeriod. Not available for Core/Enterprise installations.",
118
+ inputSchema: {
119
+ type: "object",
120
+ properties: {
121
+ name: {
122
+ type: "string",
123
+ description: "Name of the database/bucket to update",
124
+ },
125
+ newName: {
126
+ type: "string",
127
+ description: "New name for the database/bucket (Cloud Serverless only)",
128
+ },
129
+ description: {
130
+ type: "string",
131
+ description: "Description for the bucket (Cloud Serverless only)",
132
+ },
133
+ maxTables: {
134
+ type: "number",
135
+ description: "Maximum number of tables (Cloud Dedicated/Clustered only)",
136
+ minimum: 1,
137
+ },
138
+ maxColumnsPerTable: {
139
+ type: "number",
140
+ description: "Maximum columns per table (Cloud Dedicated/Clustered only)",
141
+ minimum: 1,
142
+ },
143
+ retentionPeriod: {
144
+ type: "number",
145
+ description: "Retention period in nanoseconds (Cloud Dedicated/Clustered and Cloud Serverless)",
146
+ minimum: 0,
147
+ },
148
+ },
149
+ required: ["name"],
150
+ additionalProperties: false,
151
+ },
152
+ zodSchema: z.object({
153
+ name: z.string().describe("Name of the database/bucket to update"),
154
+ newName: z
155
+ .string()
156
+ .optional()
157
+ .describe("New name for the database/bucket (Cloud Serverless only)"),
158
+ description: z
159
+ .string()
160
+ .optional()
161
+ .describe("Description for the bucket (Cloud Serverless only)"),
162
+ maxTables: z
163
+ .number()
164
+ .min(1)
165
+ .optional()
166
+ .describe("Maximum number of tables (Cloud Dedicated/Clustered only)"),
167
+ maxColumnsPerTable: z
168
+ .number()
169
+ .min(1)
170
+ .optional()
171
+ .describe("Maximum columns per table (Cloud Dedicated/Clustered only)"),
172
+ retentionPeriod: z
173
+ .number()
174
+ .min(0)
175
+ .optional()
176
+ .describe("Retention period in nanoseconds"),
177
+ }),
178
+ handler: async (args) => {
179
+ try {
180
+ const config = {};
181
+ if (args.maxTables !== undefined)
182
+ config.maxTables = args.maxTables;
183
+ if (args.maxColumnsPerTable !== undefined)
184
+ config.maxColumnsPerTable = args.maxColumnsPerTable;
185
+ if (args.newName !== undefined)
186
+ config.name = args.newName;
187
+ if (args.description !== undefined)
188
+ config.description = args.description;
189
+ if (args.retentionPeriod !== undefined)
190
+ config.retentionPeriod = args.retentionPeriod;
191
+ if (Object.keys(config).length === 0) {
192
+ throw new Error("At least one configuration parameter must be provided");
193
+ }
194
+ await influxService.database.updateDatabase(args.name, config);
195
+ const updatedFields = Object.keys(config)
196
+ .map((key) => `${key}: ${config[key]}`)
197
+ .join(", ");
198
+ return {
199
+ content: [
200
+ {
201
+ type: "text",
202
+ text: `Database '${args.name}' updated successfully with: ${updatedFields}`,
203
+ },
204
+ ],
205
+ };
206
+ }
207
+ catch (error) {
208
+ return {
209
+ content: [
210
+ {
211
+ type: "text",
212
+ text: `Error: ${error.message}`,
213
+ },
214
+ ],
215
+ isError: true,
216
+ };
217
+ }
218
+ },
219
+ },
220
+ {
221
+ name: "delete_database",
222
+ description: "Delete a database from InfluxDB. Use the exact database name as returned by the list_databases tool.",
223
+ inputSchema: {
224
+ type: "object",
225
+ properties: {
226
+ name: {
227
+ type: "string",
228
+ description: "Name of the database to delete (use exact name from database list)",
229
+ },
230
+ },
231
+ required: ["name"],
232
+ additionalProperties: false,
233
+ },
234
+ zodSchema: z.object({
235
+ name: z.string().describe("Name of the database to delete"),
236
+ }),
237
+ handler: async (args) => {
238
+ try {
239
+ await influxService.database.deleteDatabase(args.name);
240
+ return {
241
+ content: [
242
+ {
243
+ type: "text",
244
+ text: `Database '${args.name}' deleted successfully`,
245
+ },
246
+ ],
247
+ };
248
+ }
249
+ catch (error) {
250
+ return {
251
+ content: [
252
+ {
253
+ type: "text",
254
+ text: `Error: ${error.message}`,
255
+ },
256
+ ],
257
+ isError: true,
258
+ };
259
+ }
260
+ },
261
+ },
262
+ {
263
+ name: "list_databases",
264
+ description: "List all databases in the InfluxDB instance (all versions). Returns database names, count, and status information.",
265
+ inputSchema: {
266
+ type: "object",
267
+ properties: {},
268
+ additionalProperties: false,
269
+ },
270
+ zodSchema: z.object({}),
271
+ handler: async () => {
272
+ try {
273
+ const databases = await influxService.database.listDatabases();
274
+ const databaseList = databases.map((db) => db.name).join(", ");
275
+ const count = databases.length;
276
+ return {
277
+ content: [
278
+ {
279
+ type: "text",
280
+ text: `Found ${count} database${count !== 1 ? "s" : ""} in InfluxDB instance:\n${databaseList || "None"}\n\nDatabase details:\n${JSON.stringify(databases, null, 2)}`,
281
+ },
282
+ ],
283
+ };
284
+ }
285
+ catch (error) {
286
+ return {
287
+ content: [
288
+ {
289
+ type: "text",
290
+ text: `Error listing databases: ${error.message}`,
291
+ },
292
+ ],
293
+ isError: true,
294
+ };
295
+ }
296
+ },
297
+ },
298
+ ];
299
+ }