metabase-ai-assistant 3.4.1 → 3.4.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_MCP.md CHANGED
@@ -180,6 +180,9 @@ After updating the configuration file, restart your MCP client to load the new s
180
180
  ## Features Summary
181
181
 
182
182
  ### Currently Available
183
+ - **Async Query Management** (for long-running queries)
184
+ - **Smart Response Optimization** (no truncation for DDL/definitions)
185
+ - **Table Profiling** (dim/ref table detection)
183
186
  - Metabase API integration
184
187
  - SQL query execution
185
188
  - Question/Dashboard creation
@@ -213,7 +216,8 @@ After updating the configuration file, restart your MCP client to load the new s
213
216
  ```json
214
217
  {
215
218
  "database_id": 1,
216
- "sql": "SELECT * FROM table_name LIMIT 10"
219
+ "sql": "SELECT * FROM table_name LIMIT 10",
220
+ "full_results": false // Optional: Set true to disable truncation (useful for DDL)
217
221
  }
218
222
  ```
219
223
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metabase-ai-assistant",
3
- "version": "3.4.1",
3
+ "version": "3.4.3",
4
4
  "mcpName": "io.github.enessari/metabase-ai-assistant",
5
5
  "description": "The most powerful MCP Server for Metabase - 111+ tools for AI-powered SQL generation, dashboard automation, user management & enterprise BI. Works with Claude, Cursor, and any MCP-compatible AI.",
6
6
  "main": "src/index.js",
package/src/mcp/server.js CHANGED
@@ -3943,7 +3943,13 @@ class MetabaseMCPServer {
3943
3943
  output += `⏱️ Elapsed: ${elapsedSeconds} seconds\\n`;
3944
3944
 
3945
3945
  if (job.status === 'running' || job.status === 'pending') {
3946
- output += `\\n💡 Query is still running. Check again later or use \`sql_cancel\` to stop.`;
3946
+ let waitSeconds = 3;
3947
+ if (elapsedSeconds > 60) waitSeconds = 30;
3948
+ else if (elapsedSeconds > 30) waitSeconds = 10;
3949
+ else if (elapsedSeconds > 10) waitSeconds = 5;
3950
+
3951
+ output += `\\n💡 Query is still running. Please wait **${waitSeconds} seconds** before checking again.\\n`;
3952
+ output += `(Use \`sql_cancel\` to stop if needed)`;
3947
3953
  } else if (job.status === 'complete') {
3948
3954
  const rows = job.result?.data?.rows || [];
3949
3955
  const columns = job.result?.data?.cols || [];
@@ -4192,11 +4198,39 @@ class MetabaseMCPServer {
4192
4198
 
4193
4199
  async handleAddCardToDashboard(args) {
4194
4200
  try {
4201
+ // Normalize position parameters (support both flat and nested structure)
4202
+ // AI sometimes sends flat: { row: 0, col: 0, size_x: 4 }
4203
+ // Or nested: { position: { row: 0, col: 0, sizeX: 4 } }
4204
+ let position = args.position || {};
4205
+
4206
+ // If args has direct position props, merge them
4207
+ if (args.row !== undefined) position.row = args.row;
4208
+ if (args.col !== undefined) position.col = args.col;
4209
+
4210
+ // Handle size_x vs sizeX and size_y vs sizeY
4211
+ if (args.size_x !== undefined) position.sizeX = args.size_x;
4212
+ if (args.size_y !== undefined) position.sizeY = args.size_y;
4213
+ if (args.sizeX !== undefined) position.sizeX = args.sizeX;
4214
+ if (args.sizeY !== undefined) position.sizeY = args.sizeY;
4215
+
4216
+ // Map back to format expected by client
4217
+ // The client expects: Options object with optional row, col, sizeX, sizeY
4218
+ // But we need to make sure we pass the right keys to client.addCardToDashboard
4219
+
4220
+ // Create a normalized options object for the client
4221
+ const options = {
4222
+ row: position.row,
4223
+ col: position.col,
4224
+ sizeX: position.sizeX || position.size_x,
4225
+ sizeY: position.sizeY || position.size_y,
4226
+ parameter_mappings: args.parameter_mappings || []
4227
+ };
4228
+
4195
4229
  const result = await this.metabaseClient.addCardToDashboard(
4196
4230
  args.dashboard_id,
4197
4231
  args.question_id,
4198
- args.position,
4199
- args.parameter_mappings
4232
+ options, // Pass normalized options instead of raw args
4233
+ args.parameter_mappings // Double pass, just in case (client signature check needed)
4200
4234
  );
4201
4235
 
4202
4236
  // VERIFICATION: Check if card was actually added
@@ -60,6 +60,39 @@ export class MetabaseClient {
60
60
  }
61
61
  }
62
62
 
63
+ /**
64
+ * Generic request wrapper for Metabase API
65
+ * Used by MCP handlers that need arbitrary API access
66
+ */
67
+ async request(method, endpoint, data = null, config = {}) {
68
+ await this.ensureAuthenticated();
69
+
70
+ // Normalize method
71
+ const methodUpper = method.toUpperCase();
72
+
73
+ const requestConfig = {
74
+ ...config,
75
+ method: methodUpper,
76
+ url: endpoint,
77
+ data: data
78
+ };
79
+
80
+ // For GET requests with data, move to params if not already set
81
+ if (methodUpper === 'GET' && data && !requestConfig.params) {
82
+ requestConfig.params = data;
83
+ delete requestConfig.data;
84
+ }
85
+
86
+ try {
87
+ const response = await this.client.request(requestConfig);
88
+ return response.data;
89
+ } catch (error) {
90
+ const errorMsg = error.response?.data?.message || error.message;
91
+ logger.error(`API Request Failed: ${methodUpper} ${endpoint}`, { error: errorMsg });
92
+ throw new Error(`Metabase API Error: ${errorMsg}`);
93
+ }
94
+ }
95
+
63
96
  // Database Operations
64
97
  async getDatabases() {
65
98
  await this.ensureAuthenticated();