@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,75 @@
1
+ /**
2
+ * Health and Monitoring Tools
3
+ */
4
+ import { z } from "zod";
5
+ export function createHealthTools(influxService) {
6
+ return [
7
+ {
8
+ name: "health_check",
9
+ description: "Check current connection status to the InfluxDB instance. Returns connection status, configuration, and available endpoint results. Health assessment is flexible - if any check passes (client initialization, /health endpoint, or /ping), the instance is considered healthy. Available checks depend on the InfluxDB product type and token configuration.",
10
+ inputSchema: {
11
+ type: "object",
12
+ properties: {},
13
+ additionalProperties: false,
14
+ },
15
+ zodSchema: z.object({}),
16
+ handler: async () => {
17
+ try {
18
+ const connectionInfo = influxService.getConnectionInfo();
19
+ const influxType = influxService["baseConnection"]?.["config"]?.influx?.type ||
20
+ "unknown";
21
+ let healthStatus = null;
22
+ let pingResult = null;
23
+ let hasAnySuccess = false;
24
+ try {
25
+ healthStatus = await influxService.getHealthStatus();
26
+ if (healthStatus.status === "pass")
27
+ hasAnySuccess = true;
28
+ }
29
+ catch (_error) { }
30
+ try {
31
+ pingResult = await influxService.ping();
32
+ if (pingResult.ok === true)
33
+ hasAnySuccess = true;
34
+ }
35
+ catch (_error) { }
36
+ if (connectionInfo.isDataClientInitialized)
37
+ hasAnySuccess = true;
38
+ const healthInfo = {
39
+ timestamp: new Date().toISOString(),
40
+ connection: {
41
+ status: hasAnySuccess ? "healthy" : "failed",
42
+ url: connectionInfo.url,
43
+ hasToken: connectionInfo.hasToken,
44
+ database: connectionInfo.database,
45
+ type: influxType,
46
+ },
47
+ health: healthStatus,
48
+ ping: pingResult,
49
+ };
50
+ const statusText = hasAnySuccess ? "✅ HEALTHY" : "❌ FAILED";
51
+ const detailsText = JSON.stringify(healthInfo, null, 2);
52
+ return {
53
+ content: [
54
+ {
55
+ type: "text",
56
+ text: `InfluxDB Health Check: ${statusText}\n\nNote: Health assessment is based on available endpoints for your InfluxDB product type and token configuration. If any check passes, the instance is considered operational.\n\nConnection Details:\n${detailsText}`,
57
+ },
58
+ ],
59
+ };
60
+ }
61
+ catch (error) {
62
+ return {
63
+ content: [
64
+ {
65
+ type: "text",
66
+ text: `Error during health check: ${error.message}`,
67
+ },
68
+ ],
69
+ isError: true,
70
+ };
71
+ }
72
+ },
73
+ },
74
+ ];
75
+ }
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Help and Documentation Tools
3
+ */
4
+ import { z } from "zod";
5
+ export function createHelpTools(influxService) {
6
+ return [
7
+ {
8
+ name: "load_database_context",
9
+ description: "Check for and load custom database context if available. Always check this first as it can significantly speed up analysis and clarify data nuances. User-provided context is optional but when present, it contains valuable information about database structure, business context, or personal notes that can guide more accurate analysis.",
10
+ inputSchema: {
11
+ type: "object",
12
+ properties: {},
13
+ additionalProperties: false,
14
+ },
15
+ zodSchema: z.object({}),
16
+ handler: async (_args) => {
17
+ try {
18
+ const contextFile = await influxService.contextFile.loadContextFile();
19
+ if (!contextFile) {
20
+ return {
21
+ content: [
22
+ {
23
+ type: "text",
24
+ text: `No custom context file found.
25
+
26
+ User-provided context is optional. If users want to provide context, they can:
27
+ 1. Create a file in /context/ folder (any .json, .txt, .md file)
28
+ 2. Or create a file with 'context' in the name (.json, .txt, .md)
29
+
30
+ Context can include anything helpful:
31
+ - Database schema and measurement descriptions
32
+ - Business context or data purposes
33
+ - Simple notes about their setup
34
+ - Personal context ("I'm tracking my daily activities")
35
+
36
+ Proceed with database exploration using available tools.`,
37
+ },
38
+ ],
39
+ };
40
+ }
41
+ return {
42
+ content: [
43
+ {
44
+ type: "text",
45
+ text: `Custom context loaded from: ${contextFile.name}.${contextFile.extension}
46
+
47
+ ${contextFile.content}
48
+
49
+ Use this context to guide subsequent database operations and analysis.`,
50
+ },
51
+ ],
52
+ };
53
+ }
54
+ catch (error) {
55
+ return {
56
+ content: [
57
+ {
58
+ type: "text",
59
+ text: `Error loading context: ${error.message}
60
+
61
+ Context is optional - proceed with database exploration using available tools.`,
62
+ },
63
+ ],
64
+ isError: true,
65
+ };
66
+ }
67
+ },
68
+ },
69
+ {
70
+ name: "get_help",
71
+ description: "Get help and troubleshooting guidance for InfluxDB operations. Supports specific categories or keyword search.",
72
+ inputSchema: {
73
+ type: "object",
74
+ properties: {},
75
+ additionalProperties: false,
76
+ },
77
+ zodSchema: z.object({}),
78
+ handler: async (_args) => {
79
+ try {
80
+ const helpContent = influxService.help.getHelp();
81
+ return {
82
+ content: [
83
+ {
84
+ type: "text",
85
+ text: helpContent,
86
+ },
87
+ ],
88
+ };
89
+ }
90
+ catch (error) {
91
+ return {
92
+ content: [
93
+ {
94
+ type: "text",
95
+ text: `Error getting help: ${error.message}`,
96
+ },
97
+ ],
98
+ isError: true,
99
+ };
100
+ }
101
+ },
102
+ },
103
+ ];
104
+ }
@@ -0,0 +1,180 @@
1
+ /**
2
+ * Query and Schema Tools
3
+ */
4
+ import { z } from "zod";
5
+ export function createQueryTools(influxService) {
6
+ return [
7
+ {
8
+ name: "execute_query",
9
+ description: `Execute a SQL query against an InfluxDB database (all versions). Returns results in the specified format (defaults to JSON).
10
+
11
+ Large Dataset Warning: InfluxDB might contain massive time-series data. Always use COUNT(*) first to check size, then LIMIT/OFFSET for large results (>1000 rows).
12
+
13
+ Cloud Dedicated/Clustered & Cloud Serverless (v3) Requirements:
14
+ - GROUP BY: Include all group columns in SELECT (e.g., SELECT place, COUNT(*) ... GROUP BY place)
15
+ - Aggregations: Cast and alias COUNT (e.g., CAST(COUNT(*) AS DOUBLE) AS count)
16
+ - Note: Both products require CAST for all aggregation functions (COUNT, SUM, AVG, MIN, MAX) to ensure results appear properly in response`,
17
+ inputSchema: {
18
+ type: "object",
19
+ properties: {
20
+ database: {
21
+ type: "string",
22
+ description: "Name of the database/bucket to query",
23
+ },
24
+ query: {
25
+ type: "string",
26
+ description: "SQL query to execute.",
27
+ },
28
+ format: {
29
+ type: "string",
30
+ enum: ["json", "csv", "parquet", "jsonl", "pretty"],
31
+ description: "Output format for query results",
32
+ default: "json",
33
+ },
34
+ },
35
+ required: ["database", "query"],
36
+ additionalProperties: false,
37
+ },
38
+ zodSchema: z.object({
39
+ database: z.string().describe("Name of the database/bucket to query"),
40
+ query: z.string().describe("SQL query to execute"),
41
+ format: z
42
+ .enum(["json", "csv", "parquet", "jsonl", "pretty"])
43
+ .optional()
44
+ .default("json"),
45
+ }),
46
+ handler: async (args) => {
47
+ try {
48
+ const result = await influxService.query.executeQuery(args.query, args.database, {
49
+ format: args.format,
50
+ });
51
+ let resultText = "";
52
+ if (args.format === "json") {
53
+ resultText = `Query executed successfully:\n${JSON.stringify(result, null, 2)}`;
54
+ }
55
+ else {
56
+ resultText = `Query executed successfully (${args.format} format):\n${result}`;
57
+ }
58
+ return {
59
+ content: [
60
+ {
61
+ type: "text",
62
+ text: resultText,
63
+ },
64
+ ],
65
+ };
66
+ }
67
+ catch (error) {
68
+ return {
69
+ content: [
70
+ {
71
+ type: "text",
72
+ text: `Error: ${error.message}`,
73
+ },
74
+ ],
75
+ isError: true,
76
+ };
77
+ }
78
+ },
79
+ },
80
+ {
81
+ name: "get_measurements",
82
+ description: "Get a list of all measurements (tables) in a database/bucket (all versions). Uses the InfluxDB information_schema.columns to discover tables.",
83
+ inputSchema: {
84
+ type: "object",
85
+ properties: {
86
+ database: {
87
+ type: "string",
88
+ description: "Name of the database/bucket to list measurements from",
89
+ },
90
+ },
91
+ required: ["database"],
92
+ additionalProperties: false,
93
+ },
94
+ zodSchema: z.object({
95
+ database: z
96
+ .string()
97
+ .describe("Name of the database/bucket to list measurements from"),
98
+ }),
99
+ handler: async (args) => {
100
+ try {
101
+ const measurements = await influxService.query.getMeasurements(args.database);
102
+ const measurementList = measurements.map((m) => m.name).join(", ");
103
+ const count = measurements.length;
104
+ return {
105
+ content: [
106
+ {
107
+ type: "text",
108
+ text: `Found ${count} measurement${count !== 1 ? "s" : ""} in database '${args.database}':\n${measurementList || "None"}`,
109
+ },
110
+ ],
111
+ };
112
+ }
113
+ catch (error) {
114
+ return {
115
+ content: [
116
+ {
117
+ type: "text",
118
+ text: `Error: ${error.message}`,
119
+ },
120
+ ],
121
+ isError: true,
122
+ };
123
+ }
124
+ },
125
+ },
126
+ {
127
+ name: "get_measurement_schema",
128
+ description: "Get the schema (column information) for a specific measurement/table (all versions). Shows column names, types, and categories (time/tag/field).",
129
+ inputSchema: {
130
+ type: "object",
131
+ properties: {
132
+ database: {
133
+ type: "string",
134
+ description: "Name of the database/bucket containing the measurement",
135
+ },
136
+ measurement: {
137
+ type: "string",
138
+ description: "Name of the measurement to describe",
139
+ },
140
+ },
141
+ required: ["database", "measurement"],
142
+ additionalProperties: false,
143
+ },
144
+ zodSchema: z.object({
145
+ database: z
146
+ .string()
147
+ .describe("Name of the database/bucket containing the measurement"),
148
+ measurement: z.string().describe("Name of the measurement to describe"),
149
+ }),
150
+ handler: async (args) => {
151
+ try {
152
+ const schema = await influxService.query.getMeasurementSchema(args.measurement, args.database);
153
+ const columnInfo = schema.columns
154
+ .map((col) => ` - ${col.name}: ${col.type} (${col.category})`)
155
+ .join("\n");
156
+ const count = schema.columns.length;
157
+ return {
158
+ content: [
159
+ {
160
+ type: "text",
161
+ text: `Schema for measurement '${args.measurement}' in database '${args.database}':\n${count} column${count !== 1 ? "s" : ""}:\n${columnInfo}`,
162
+ },
163
+ ],
164
+ };
165
+ }
166
+ catch (error) {
167
+ return {
168
+ content: [
169
+ {
170
+ type: "text",
171
+ text: `Error: ${error.message}`,
172
+ },
173
+ ],
174
+ isError: true,
175
+ };
176
+ }
177
+ },
178
+ },
179
+ ];
180
+ }
@@ -0,0 +1,308 @@
1
+ /**
2
+ * Schema Management Tools for InfluxDB Cloud Serverless
3
+ *
4
+ * Provides tools for managing measurement schemas in Cloud Serverless buckets.
5
+ * These tools are only available for Cloud Serverless instances with explicit schema type.
6
+ * Explicit schema type is not implemented in v3 InfluxDB cloud serverless as of now.
7
+ */
8
+ import { z } from "zod";
9
+ export function createSchemaTools(influxService) {
10
+ return [
11
+ {
12
+ name: "serverless_list_schemas",
13
+ description: "List all measurement schemas in a Cloud Serverless bucket. Only available for buckets with explicit schema type. Shows schema names, column definitions, and metadata.",
14
+ inputSchema: {
15
+ type: "object",
16
+ properties: {
17
+ bucketName: {
18
+ type: "string",
19
+ description: "Name of the bucket to list schemas from",
20
+ },
21
+ },
22
+ required: ["bucketName"],
23
+ additionalProperties: false,
24
+ },
25
+ zodSchema: z.object({
26
+ bucketName: z
27
+ .string()
28
+ .describe("Name of the bucket to list schemas from"),
29
+ }),
30
+ handler: async (args) => {
31
+ try {
32
+ const schemas = await influxService.schema.listSchemas(args.bucketName);
33
+ const schemaList = schemas.map((schema) => schema.name).join(", ");
34
+ const count = schemas.length;
35
+ return {
36
+ content: [
37
+ {
38
+ type: "text",
39
+ text: `Found ${count} schema${count !== 1 ? "s" : ""} in bucket '${args.bucketName}':\n${schemaList || "None"}\n\nSchema details:\n${JSON.stringify(schemas, null, 2)}`,
40
+ },
41
+ ],
42
+ };
43
+ }
44
+ catch (error) {
45
+ return {
46
+ content: [
47
+ {
48
+ type: "text",
49
+ text: `Error: ${error.message}`,
50
+ },
51
+ ],
52
+ isError: true,
53
+ };
54
+ }
55
+ },
56
+ },
57
+ {
58
+ name: "serverless_get_schema",
59
+ description: "Get detailed information about a specific measurement schema in a Cloud Serverless bucket. Shows column definitions, data types, and schema metadata.",
60
+ inputSchema: {
61
+ type: "object",
62
+ properties: {
63
+ bucketName: {
64
+ type: "string",
65
+ description: "Name of the bucket containing the schema",
66
+ },
67
+ schemaName: {
68
+ type: "string",
69
+ description: "Name of the measurement schema to retrieve",
70
+ },
71
+ },
72
+ required: ["bucketName", "schemaName"],
73
+ additionalProperties: false,
74
+ },
75
+ zodSchema: z.object({
76
+ bucketName: z
77
+ .string()
78
+ .describe("Name of the bucket containing the schema"),
79
+ schemaName: z
80
+ .string()
81
+ .describe("Name of the measurement schema to retrieve"),
82
+ }),
83
+ handler: async (args) => {
84
+ try {
85
+ const schema = await influxService.schema.getSchema(args.bucketName, args.schemaName);
86
+ return {
87
+ content: [
88
+ {
89
+ type: "text",
90
+ text: `Schema '${args.schemaName}' details:\n\n${JSON.stringify(schema, null, 2)}`,
91
+ },
92
+ ],
93
+ };
94
+ }
95
+ catch (error) {
96
+ return {
97
+ content: [
98
+ {
99
+ type: "text",
100
+ text: `Error: ${error.message}`,
101
+ },
102
+ ],
103
+ isError: true,
104
+ };
105
+ }
106
+ },
107
+ },
108
+ {
109
+ name: "serverless_create_schema",
110
+ description: "Create a new measurement schema in a Cloud Serverless bucket with explicit schema type. Define columns with their types (tag, field, timestamp) and data types.",
111
+ inputSchema: {
112
+ type: "object",
113
+ properties: {
114
+ bucketName: {
115
+ type: "string",
116
+ description: "Name of the bucket to create the schema in",
117
+ },
118
+ schemaName: {
119
+ type: "string",
120
+ description: "Name of the measurement schema to create",
121
+ },
122
+ columns: {
123
+ type: "array",
124
+ description: "Array of column definitions for the schema",
125
+ items: {
126
+ type: "object",
127
+ properties: {
128
+ name: {
129
+ type: "string",
130
+ description: "Column name",
131
+ },
132
+ type: {
133
+ type: "string",
134
+ enum: ["tag", "field", "timestamp"],
135
+ description: "Column type: tag (indexed metadata), field (actual data), or timestamp",
136
+ },
137
+ dataType: {
138
+ type: "string",
139
+ enum: ["string", "float", "integer", "boolean", "time"],
140
+ description: "Data type for the column (required for field columns, optional for others)",
141
+ },
142
+ },
143
+ required: ["name", "type"],
144
+ additionalProperties: false,
145
+ },
146
+ minItems: 1,
147
+ },
148
+ },
149
+ required: ["bucketName", "schemaName", "columns"],
150
+ additionalProperties: false,
151
+ },
152
+ zodSchema: z.object({
153
+ bucketName: z
154
+ .string()
155
+ .describe("Name of the bucket to create the schema in"),
156
+ schemaName: z
157
+ .string()
158
+ .describe("Name of the measurement schema to create"),
159
+ columns: z
160
+ .array(z.object({
161
+ name: z.string().describe("Column name"),
162
+ type: z
163
+ .enum(["tag", "field", "timestamp"])
164
+ .describe("Column type"),
165
+ dataType: z
166
+ .enum(["string", "float", "integer", "boolean", "time"])
167
+ .optional()
168
+ .describe("Data type for the column"),
169
+ }))
170
+ .min(1)
171
+ .describe("Array of column definitions"),
172
+ }),
173
+ handler: async (args) => {
174
+ try {
175
+ const config = {
176
+ name: args.schemaName,
177
+ bucketName: args.bucketName,
178
+ columns: args.columns,
179
+ };
180
+ await influxService.schema.createSchema(config);
181
+ return {
182
+ content: [
183
+ {
184
+ type: "text",
185
+ text: `Schema '${args.schemaName}' created successfully in bucket '${args.bucketName}'`,
186
+ },
187
+ ],
188
+ };
189
+ }
190
+ catch (error) {
191
+ return {
192
+ content: [
193
+ {
194
+ type: "text",
195
+ text: `Error: ${error.message}`,
196
+ },
197
+ ],
198
+ isError: true,
199
+ };
200
+ }
201
+ },
202
+ },
203
+ {
204
+ name: "serverless_update_schema",
205
+ description: "Add new columns to an existing measurement schema in a Cloud Serverless bucket. IMPORTANT: You can only ADD new columns, not modify existing ones. The endpoint requires ALL columns (existing + new) to be sent. Use get_schema first to retrieve current columns, then include them along with new columns in this update.",
206
+ inputSchema: {
207
+ type: "object",
208
+ properties: {
209
+ bucketName: {
210
+ type: "string",
211
+ description: "Name of the bucket containing the schema",
212
+ },
213
+ schemaName: {
214
+ type: "string",
215
+ description: "Current name of the measurement schema to update",
216
+ },
217
+ columns: {
218
+ type: "array",
219
+ description: "Complete array of ALL column definitions (existing columns + new columns to add). Must include all current columns plus any new ones you want to add.",
220
+ items: {
221
+ type: "object",
222
+ properties: {
223
+ name: {
224
+ type: "string",
225
+ description: "Column name",
226
+ },
227
+ type: {
228
+ type: "string",
229
+ enum: ["tag", "field", "timestamp"],
230
+ description: "Column type: tag (indexed metadata), field (actual data), or timestamp",
231
+ },
232
+ dataType: {
233
+ type: "string",
234
+ enum: ["string", "float", "integer", "boolean", "time"],
235
+ description: "Data type for the column",
236
+ },
237
+ },
238
+ required: ["name", "type"],
239
+ additionalProperties: false,
240
+ },
241
+ },
242
+ },
243
+ required: ["bucketName", "schemaName"],
244
+ additionalProperties: false,
245
+ },
246
+ zodSchema: z.object({
247
+ bucketName: z
248
+ .string()
249
+ .describe("Name of the bucket containing the schema"),
250
+ schemaName: z
251
+ .string()
252
+ .describe("Current name of the measurement schema to update"),
253
+ columns: z
254
+ .array(z.object({
255
+ name: z.string().describe("Column name"),
256
+ type: z
257
+ .enum(["tag", "field", "timestamp"])
258
+ .describe("Column type"),
259
+ dataType: z
260
+ .enum(["string", "float", "integer", "boolean", "time"])
261
+ .optional()
262
+ .describe("Data type for the column"),
263
+ }))
264
+ .optional()
265
+ .describe("Updated array of column definitions"),
266
+ }),
267
+ handler: async (args) => {
268
+ try {
269
+ const success = await influxService.schema.updateSchema(args.bucketName, args.schemaName, {
270
+ columns: args.columns,
271
+ });
272
+ if (success) {
273
+ return {
274
+ content: [
275
+ {
276
+ type: "text",
277
+ text: `Schema '${args.schemaName}' updated successfully. New columns have been added to the existing schema.`,
278
+ },
279
+ ],
280
+ };
281
+ }
282
+ else {
283
+ return {
284
+ content: [
285
+ {
286
+ type: "text",
287
+ text: `Failed to update schema '${args.schemaName}'.`,
288
+ },
289
+ ],
290
+ isError: true,
291
+ };
292
+ }
293
+ }
294
+ catch (error) {
295
+ return {
296
+ content: [
297
+ {
298
+ type: "text",
299
+ text: `Error: ${error.message}`,
300
+ },
301
+ ],
302
+ isError: true,
303
+ };
304
+ }
305
+ },
306
+ },
307
+ ];
308
+ }