metabase-agent-mcp-server 0.1.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.
- package/.dockerignore +4 -0
- package/.env.example +5 -0
- package/.prettierrc +5 -0
- package/Dockerfile +17 -0
- package/README.md +106 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +252 -0
- package/dist/index.js.map +1 -0
- package/dist/metabase-client.d.ts +203 -0
- package/dist/metabase-client.js +75 -0
- package/dist/metabase-client.js.map +1 -0
- package/dist/utils.d.ts +13 -0
- package/dist/utils.js +48 -0
- package/dist/utils.js.map +1 -0
- package/eslint.config.mjs +10 -0
- package/package.json +47 -0
- package/src/__tests__/metabase-client.test.ts +203 -0
- package/src/index.ts +338 -0
- package/src/metabase-client.ts +332 -0
- package/tsconfig.json +17 -0
package/.dockerignore
ADDED
package/.env.example
ADDED
package/.prettierrc
ADDED
package/Dockerfile
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
FROM node:20-slim AS build
|
|
2
|
+
|
|
3
|
+
WORKDIR /app
|
|
4
|
+
COPY package.json package-lock.json* ./
|
|
5
|
+
RUN npm ci
|
|
6
|
+
COPY tsconfig.json ./
|
|
7
|
+
COPY src ./src
|
|
8
|
+
RUN npm run build
|
|
9
|
+
|
|
10
|
+
FROM node:20-slim
|
|
11
|
+
|
|
12
|
+
WORKDIR /app
|
|
13
|
+
COPY package.json package-lock.json* ./
|
|
14
|
+
RUN npm ci --omit=dev
|
|
15
|
+
COPY --from=build /app/dist ./dist
|
|
16
|
+
|
|
17
|
+
ENTRYPOINT ["node", "dist/index.js"]
|
package/README.md
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Metabase Agent MCP Server
|
|
2
|
+
|
|
3
|
+
An MCP (Model Context Protocol) server that exposes [Metabase's Agent API](https://www.metabase.com/docs/latest/ai/agent-api) as tools for AI assistants like Claude, LibreChat, or any MCP-compatible client.
|
|
4
|
+
|
|
5
|
+
The Agent API is a versioned REST API for building headless, agentic BI applications on top of Metabase's semantic layer. This MCP server wraps the Agent API v1 endpoints so that LLMs can discover tables and metrics, inspect fields, and run queries — all scoped to the permissions of the configured API key.
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
- **Metabase** v0.59+ with a Pro/Enterprise license (the Agent API is a paid feature)
|
|
10
|
+
- A **Metabase API key** created in Admin > Settings > Authentication > API Keys
|
|
11
|
+
- **Node.js** 20+ (for local usage) or **Docker**
|
|
12
|
+
|
|
13
|
+
## Configuration
|
|
14
|
+
|
|
15
|
+
The server reads two required environment variables:
|
|
16
|
+
|
|
17
|
+
| Variable | Description |
|
|
18
|
+
| ------------------ | ------------------------------------------------- |
|
|
19
|
+
| `METABASE_URL` | Base URL of your Metabase instance (e.g. `https://metabase.example.com`) |
|
|
20
|
+
| `METABASE_API_KEY` | API key for authenticating with Metabase |
|
|
21
|
+
|
|
22
|
+
### Why API key instead of JWT?
|
|
23
|
+
|
|
24
|
+
The Metabase Agent API docs recommend JWT for per-user auth scoping. However, MCP clients like Claude Desktop and LibreChat pass static environment variables to servers — they don't support dynamic JWT generation. A Metabase API key provides a simple, static credential that works with any MCP client. The API key's permissions are determined by the Metabase user it was created for.
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
### With Claude Desktop
|
|
29
|
+
|
|
30
|
+
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"mcpServers": {
|
|
35
|
+
"metabase": {
|
|
36
|
+
"command": "node",
|
|
37
|
+
"args": ["/path/to/metabase-agent-mcp-server/dist/index.js"],
|
|
38
|
+
"env": {
|
|
39
|
+
"METABASE_URL": "https://metabase.example.com",
|
|
40
|
+
"METABASE_API_KEY": "mb_your_api_key_here"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### With LibreChat
|
|
48
|
+
|
|
49
|
+
Configure in your LibreChat MCP settings:
|
|
50
|
+
|
|
51
|
+
```yaml
|
|
52
|
+
mcpServers:
|
|
53
|
+
metabase:
|
|
54
|
+
command: node
|
|
55
|
+
args:
|
|
56
|
+
- /path/to/metabase-agent-mcp-server/dist/index.js
|
|
57
|
+
env:
|
|
58
|
+
METABASE_URL: https://metabase.example.com
|
|
59
|
+
METABASE_API_KEY: mb_your_api_key_here
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### With Docker
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
docker build -t metabase-agent-mcp .
|
|
66
|
+
|
|
67
|
+
docker run -i --rm \
|
|
68
|
+
-e METABASE_URL=https://metabase.example.com \
|
|
69
|
+
-e METABASE_API_KEY=mb_your_api_key_here \
|
|
70
|
+
metabase-agent-mcp
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Available Tools
|
|
74
|
+
|
|
75
|
+
| Tool | Description |
|
|
76
|
+
| ------------------ | --------------------------------------------------------------------------- |
|
|
77
|
+
| `search` | Search for tables and metrics (term-based and/or semantic) |
|
|
78
|
+
| `get_table` | Get details for a table: fields, related tables, metrics, measures, segments |
|
|
79
|
+
| `get_metric` | Get details for a metric: queryable dimensions, segments |
|
|
80
|
+
| `get_field_values` | Get statistics and sample values for a table or metric field |
|
|
81
|
+
| `run_query` | Construct and execute a query in one step |
|
|
82
|
+
|
|
83
|
+
### Typical workflow
|
|
84
|
+
|
|
85
|
+
1. **Search** for relevant tables or metrics using `search`
|
|
86
|
+
2. **Inspect** a table (`get_table`) or metric (`get_metric`) to see its fields and schema
|
|
87
|
+
3. **Explore** field values with `get_field_values` if you need to discover valid filter values
|
|
88
|
+
4. **Query** using `run_query` to get results
|
|
89
|
+
|
|
90
|
+
## Development
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
npm install
|
|
94
|
+
npm run build
|
|
95
|
+
npm start
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Run tests:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
npm test
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## License
|
|
105
|
+
|
|
106
|
+
MIT
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { MetabaseClient } from "./metabase-client.js";
|
|
6
|
+
const METABASE_URL = process.env.METABASE_URL;
|
|
7
|
+
const METABASE_API_KEY = process.env.METABASE_API_KEY;
|
|
8
|
+
if (!METABASE_URL || !METABASE_API_KEY) {
|
|
9
|
+
console.error("Required environment variables: METABASE_URL, METABASE_API_KEY");
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
const client = new MetabaseClient({
|
|
13
|
+
url: METABASE_URL,
|
|
14
|
+
apiKey: METABASE_API_KEY,
|
|
15
|
+
});
|
|
16
|
+
const server = new McpServer({
|
|
17
|
+
name: "metabase-agent",
|
|
18
|
+
version: "0.1.0",
|
|
19
|
+
});
|
|
20
|
+
async function handleToolCall(fn, format) {
|
|
21
|
+
try {
|
|
22
|
+
const result = await fn();
|
|
23
|
+
return { content: [{ type: "text", text: format(result) }] };
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
27
|
+
return { content: [{ type: "text", text: msg }], isError: true };
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
const json = (v) => JSON.stringify(v, null, 2);
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
// Tool: search
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
server.tool("search", "Search for tables and metrics in Metabase. Supports term-based and semantic search queries. Results are ranked using Reciprocal Rank Fusion when both query types are provided.", {
|
|
35
|
+
term_queries: z
|
|
36
|
+
.array(z.string().min(1))
|
|
37
|
+
.optional()
|
|
38
|
+
.describe("Term-based search queries"),
|
|
39
|
+
semantic_queries: z
|
|
40
|
+
.array(z.string().min(1))
|
|
41
|
+
.optional()
|
|
42
|
+
.describe("Semantic search queries"),
|
|
43
|
+
}, async ({ term_queries, semantic_queries }) => handleToolCall(() => client.search({ term_queries, semantic_queries }), json));
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
// Tool: get_table
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
server.tool("get_table", "Get details for a table including fields, related tables, metrics, measures, and segments.", {
|
|
48
|
+
id: z.number().int().min(1).describe("Table ID"),
|
|
49
|
+
with_fields: z
|
|
50
|
+
.boolean()
|
|
51
|
+
.optional()
|
|
52
|
+
.describe("Include table fields (default: true)"),
|
|
53
|
+
with_field_values: z
|
|
54
|
+
.boolean()
|
|
55
|
+
.optional()
|
|
56
|
+
.describe("Include sample field values (default: true)"),
|
|
57
|
+
with_related_tables: z
|
|
58
|
+
.boolean()
|
|
59
|
+
.optional()
|
|
60
|
+
.describe("Include related tables via FK (default: true)"),
|
|
61
|
+
with_metrics: z
|
|
62
|
+
.boolean()
|
|
63
|
+
.optional()
|
|
64
|
+
.describe("Include metrics associated with this table (default: true)"),
|
|
65
|
+
with_measures: z
|
|
66
|
+
.boolean()
|
|
67
|
+
.optional()
|
|
68
|
+
.describe("Include reusable measure definitions (default: false)"),
|
|
69
|
+
with_segments: z
|
|
70
|
+
.boolean()
|
|
71
|
+
.optional()
|
|
72
|
+
.describe("Include predefined filter segments (default: false)"),
|
|
73
|
+
}, async (args) => handleToolCall(() => client.getTable(args.id, {
|
|
74
|
+
withFields: args.with_fields,
|
|
75
|
+
withFieldValues: args.with_field_values,
|
|
76
|
+
withRelatedTables: args.with_related_tables,
|
|
77
|
+
withMetrics: args.with_metrics,
|
|
78
|
+
withMeasures: args.with_measures,
|
|
79
|
+
withSegments: args.with_segments,
|
|
80
|
+
}), json));
|
|
81
|
+
// ---------------------------------------------------------------------------
|
|
82
|
+
// Tool: get_metric
|
|
83
|
+
// ---------------------------------------------------------------------------
|
|
84
|
+
server.tool("get_metric", "Get details for a metric including its queryable dimensions and segments.", {
|
|
85
|
+
id: z.number().int().min(1).describe("Metric ID"),
|
|
86
|
+
with_queryable_dimensions: z
|
|
87
|
+
.boolean()
|
|
88
|
+
.optional()
|
|
89
|
+
.describe("Include queryable dimension fields (default: true)"),
|
|
90
|
+
with_field_values: z
|
|
91
|
+
.boolean()
|
|
92
|
+
.optional()
|
|
93
|
+
.describe("Include sample field values for dimensions (default: true)"),
|
|
94
|
+
with_default_temporal_breakout: z
|
|
95
|
+
.boolean()
|
|
96
|
+
.optional()
|
|
97
|
+
.describe("Include default time dimension for temporal breakouts (default: true)"),
|
|
98
|
+
with_segments: z
|
|
99
|
+
.boolean()
|
|
100
|
+
.optional()
|
|
101
|
+
.describe("Include predefined filter segments (default: false)"),
|
|
102
|
+
}, async (args) => handleToolCall(() => client.getMetric(args.id, {
|
|
103
|
+
withQueryableDimensions: args.with_queryable_dimensions,
|
|
104
|
+
withFieldValues: args.with_field_values,
|
|
105
|
+
withDefaultTemporalBreakout: args.with_default_temporal_breakout,
|
|
106
|
+
withSegments: args.with_segments,
|
|
107
|
+
}), json));
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
109
|
+
// Tool: get_field_values
|
|
110
|
+
// ---------------------------------------------------------------------------
|
|
111
|
+
server.tool("get_field_values", "Get statistics and sample values for a specific field. Useful for understanding data distribution, valid filter values, and field characteristics.", {
|
|
112
|
+
entity_type: z
|
|
113
|
+
.enum(["table", "metric"])
|
|
114
|
+
.describe("Whether the field belongs to a table or metric"),
|
|
115
|
+
entity_id: z.number().int().min(1).describe("Table or metric ID"),
|
|
116
|
+
field_id: z
|
|
117
|
+
.string()
|
|
118
|
+
.min(1)
|
|
119
|
+
.describe("Field ID (format: 't<id>-<index>' for table fields, 'c<id>-<index>' for metric fields)"),
|
|
120
|
+
}, async ({ entity_type, entity_id, field_id }) => handleToolCall(() => client.getFieldValues(entity_type, entity_id, field_id), json));
|
|
121
|
+
// ---------------------------------------------------------------------------
|
|
122
|
+
// Shared schemas for query construction
|
|
123
|
+
// ---------------------------------------------------------------------------
|
|
124
|
+
const FilterSchema = z.union([
|
|
125
|
+
z.object({ segment_id: z.number().int() }).describe("Segment filter"),
|
|
126
|
+
z
|
|
127
|
+
.object({
|
|
128
|
+
field_id: z.string(),
|
|
129
|
+
operation: z.string(),
|
|
130
|
+
value: z.any().optional(),
|
|
131
|
+
values: z.array(z.any()).optional(),
|
|
132
|
+
bucket: z.string().optional(),
|
|
133
|
+
})
|
|
134
|
+
.describe("Field filter"),
|
|
135
|
+
]);
|
|
136
|
+
const GroupBySchema = z.object({
|
|
137
|
+
field_id: z.string(),
|
|
138
|
+
field_granularity: z
|
|
139
|
+
.enum([
|
|
140
|
+
"minute",
|
|
141
|
+
"hour",
|
|
142
|
+
"day",
|
|
143
|
+
"week",
|
|
144
|
+
"month",
|
|
145
|
+
"quarter",
|
|
146
|
+
"year",
|
|
147
|
+
"day-of-week",
|
|
148
|
+
])
|
|
149
|
+
.nullable()
|
|
150
|
+
.optional(),
|
|
151
|
+
});
|
|
152
|
+
const FieldRefSchema = z.object({
|
|
153
|
+
field_id: z.string(),
|
|
154
|
+
bucket: z.string().optional(),
|
|
155
|
+
});
|
|
156
|
+
const OrderBySchema = z.object({
|
|
157
|
+
field: FieldRefSchema,
|
|
158
|
+
direction: z.enum(["asc", "desc"]),
|
|
159
|
+
});
|
|
160
|
+
const AggregationSchema = z.union([
|
|
161
|
+
z.object({
|
|
162
|
+
function: z.literal("count"),
|
|
163
|
+
sort_order: z.enum(["asc", "desc"]).nullable().optional(),
|
|
164
|
+
}),
|
|
165
|
+
z.object({
|
|
166
|
+
field_id: z.string(),
|
|
167
|
+
function: z.enum(["avg", "count-distinct", "max", "min", "sum"]),
|
|
168
|
+
sort_order: z.enum(["asc", "desc"]).nullable().optional(),
|
|
169
|
+
}),
|
|
170
|
+
z.object({
|
|
171
|
+
measure_id: z.number().int(),
|
|
172
|
+
sort_order: z.enum(["asc", "desc"]).nullable().optional(),
|
|
173
|
+
}),
|
|
174
|
+
]);
|
|
175
|
+
// ---------------------------------------------------------------------------
|
|
176
|
+
// Tool: run_query
|
|
177
|
+
// ---------------------------------------------------------------------------
|
|
178
|
+
server.tool("run_query", `Construct and execute a query against Metabase, returning results directly.
|
|
179
|
+
|
|
180
|
+
For tables: supports filters, fields, aggregations, group_by, order_by, limit.
|
|
181
|
+
For metrics: supports filters, group_by (aggregation is defined by the metric).
|
|
182
|
+
|
|
183
|
+
Provide EITHER table_id OR metric_id, not both.
|
|
184
|
+
Row limits: 2000 for simple queries, 10000 for aggregated queries.`, {
|
|
185
|
+
table_id: z
|
|
186
|
+
.number()
|
|
187
|
+
.int()
|
|
188
|
+
.min(1)
|
|
189
|
+
.optional()
|
|
190
|
+
.describe("Table ID (mutually exclusive with metric_id)"),
|
|
191
|
+
metric_id: z
|
|
192
|
+
.number()
|
|
193
|
+
.int()
|
|
194
|
+
.min(1)
|
|
195
|
+
.optional()
|
|
196
|
+
.describe("Metric ID (mutually exclusive with table_id)"),
|
|
197
|
+
filters: z
|
|
198
|
+
.array(FilterSchema)
|
|
199
|
+
.optional()
|
|
200
|
+
.describe("Filter conditions to apply"),
|
|
201
|
+
fields: z
|
|
202
|
+
.array(FieldRefSchema)
|
|
203
|
+
.optional()
|
|
204
|
+
.describe("Specific fields to select (omit for all fields, table queries only)"),
|
|
205
|
+
aggregations: z
|
|
206
|
+
.array(AggregationSchema)
|
|
207
|
+
.optional()
|
|
208
|
+
.describe("Aggregation functions: count, avg, sum, min, max, count-distinct, or measure_id (table queries only)"),
|
|
209
|
+
group_by: z
|
|
210
|
+
.array(GroupBySchema)
|
|
211
|
+
.optional()
|
|
212
|
+
.describe("Fields to group by, with optional temporal granularity"),
|
|
213
|
+
order_by: z
|
|
214
|
+
.array(OrderBySchema)
|
|
215
|
+
.optional()
|
|
216
|
+
.describe("Order by fields. To order by aggregation, use sort_order on the aggregation instead (table queries only)"),
|
|
217
|
+
limit: z
|
|
218
|
+
.number()
|
|
219
|
+
.int()
|
|
220
|
+
.min(1)
|
|
221
|
+
.optional()
|
|
222
|
+
.describe("Maximum rows to return (table queries only)"),
|
|
223
|
+
}, async (args) => {
|
|
224
|
+
try {
|
|
225
|
+
const constructed = await client.constructQuery(args);
|
|
226
|
+
const result = await client.executeQuery({ query: constructed.query });
|
|
227
|
+
return {
|
|
228
|
+
content: [{ type: "text", text: json(result) }],
|
|
229
|
+
...(result.status === "failed" && { isError: true }),
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
catch (err) {
|
|
233
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
234
|
+
return {
|
|
235
|
+
content: [{ type: "text", text: msg }],
|
|
236
|
+
isError: true,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
// ---------------------------------------------------------------------------
|
|
241
|
+
// Start the server
|
|
242
|
+
// ---------------------------------------------------------------------------
|
|
243
|
+
async function main() {
|
|
244
|
+
const transport = new StdioServerTransport();
|
|
245
|
+
await server.connect(transport);
|
|
246
|
+
console.error("Metabase Agent MCP server running on stdio");
|
|
247
|
+
}
|
|
248
|
+
main().catch((err) => {
|
|
249
|
+
console.error("Fatal error:", err);
|
|
250
|
+
process.exit(1);
|
|
251
|
+
});
|
|
252
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
export interface MetabaseClientConfig {
|
|
2
|
+
url: string;
|
|
3
|
+
apiKey: string;
|
|
4
|
+
timeoutMs?: number;
|
|
5
|
+
}
|
|
6
|
+
export declare class MetabaseClient {
|
|
7
|
+
private baseUrl;
|
|
8
|
+
private apiKey;
|
|
9
|
+
private timeoutMs;
|
|
10
|
+
constructor(config: MetabaseClientConfig);
|
|
11
|
+
private request;
|
|
12
|
+
search(params: {
|
|
13
|
+
term_queries?: string[];
|
|
14
|
+
semantic_queries?: string[];
|
|
15
|
+
}): Promise<SearchResponse>;
|
|
16
|
+
getTable(id: number, opts?: {
|
|
17
|
+
withFields?: boolean;
|
|
18
|
+
withFieldValues?: boolean;
|
|
19
|
+
withRelatedTables?: boolean;
|
|
20
|
+
withMetrics?: boolean;
|
|
21
|
+
withMeasures?: boolean;
|
|
22
|
+
withSegments?: boolean;
|
|
23
|
+
}): Promise<Table>;
|
|
24
|
+
getFieldValues(entityType: "table" | "metric", entityId: number, fieldId: string): Promise<FieldValues>;
|
|
25
|
+
getMetric(id: number, opts?: {
|
|
26
|
+
withQueryableDimensions?: boolean;
|
|
27
|
+
withFieldValues?: boolean;
|
|
28
|
+
withDefaultTemporalBreakout?: boolean;
|
|
29
|
+
withSegments?: boolean;
|
|
30
|
+
}): Promise<Metric>;
|
|
31
|
+
constructQuery(params: ConstructQueryRequest): Promise<ConstructQueryResponse>;
|
|
32
|
+
executeQuery(params: ExecuteQueryRequest): Promise<ExecuteQueryResponse>;
|
|
33
|
+
}
|
|
34
|
+
export interface SearchResponse {
|
|
35
|
+
data: SearchResultItem[];
|
|
36
|
+
total_count: number;
|
|
37
|
+
}
|
|
38
|
+
export interface SearchResultItem {
|
|
39
|
+
id: number;
|
|
40
|
+
type: "table" | "metric";
|
|
41
|
+
name: string;
|
|
42
|
+
display_name?: string | null;
|
|
43
|
+
description?: string | null;
|
|
44
|
+
database_id?: number | null;
|
|
45
|
+
database_schema?: string | null;
|
|
46
|
+
verified?: boolean | null;
|
|
47
|
+
created_at?: string | null;
|
|
48
|
+
updated_at?: string | null;
|
|
49
|
+
}
|
|
50
|
+
export interface Field {
|
|
51
|
+
field_id: string;
|
|
52
|
+
name: string;
|
|
53
|
+
type?: "boolean" | "date" | "datetime" | "time" | "number" | "string" | null;
|
|
54
|
+
description?: string | null;
|
|
55
|
+
database_type?: string | null;
|
|
56
|
+
semantic_type?: string | null;
|
|
57
|
+
field_values?: unknown[] | null;
|
|
58
|
+
}
|
|
59
|
+
export interface Segment {
|
|
60
|
+
id: number;
|
|
61
|
+
name: string;
|
|
62
|
+
description?: string | null;
|
|
63
|
+
display_name?: string | null;
|
|
64
|
+
}
|
|
65
|
+
export interface Measure {
|
|
66
|
+
id: number;
|
|
67
|
+
name: string;
|
|
68
|
+
description?: string | null;
|
|
69
|
+
display_name?: string | null;
|
|
70
|
+
}
|
|
71
|
+
export interface MetricSummary {
|
|
72
|
+
id: number;
|
|
73
|
+
type: "metric";
|
|
74
|
+
name: string;
|
|
75
|
+
description?: string | null;
|
|
76
|
+
default_time_dimension_field_id?: string | null;
|
|
77
|
+
}
|
|
78
|
+
export interface RelatedTable {
|
|
79
|
+
id: number;
|
|
80
|
+
type: "table";
|
|
81
|
+
name: string;
|
|
82
|
+
display_name?: string | null;
|
|
83
|
+
description?: string | null;
|
|
84
|
+
database_id?: number | null;
|
|
85
|
+
database_engine?: string | null;
|
|
86
|
+
database_schema?: string | null;
|
|
87
|
+
related_by?: string | null;
|
|
88
|
+
fields?: Field[] | null;
|
|
89
|
+
}
|
|
90
|
+
export interface Table {
|
|
91
|
+
id: number;
|
|
92
|
+
type: "table" | "metric";
|
|
93
|
+
name: string;
|
|
94
|
+
display_name: string;
|
|
95
|
+
description?: string | null;
|
|
96
|
+
database_id: number;
|
|
97
|
+
database_engine: string;
|
|
98
|
+
database_schema?: string | null;
|
|
99
|
+
fields: Field[];
|
|
100
|
+
related_tables?: RelatedTable[] | null;
|
|
101
|
+
metrics?: MetricSummary[] | null;
|
|
102
|
+
measures?: Measure[] | null;
|
|
103
|
+
segments?: Segment[] | null;
|
|
104
|
+
}
|
|
105
|
+
export interface Metric {
|
|
106
|
+
id: number;
|
|
107
|
+
type: "metric";
|
|
108
|
+
name: string;
|
|
109
|
+
description?: string | null;
|
|
110
|
+
verified?: boolean | null;
|
|
111
|
+
default_time_dimension_field_id?: string | null;
|
|
112
|
+
queryable_dimensions?: Field[] | null;
|
|
113
|
+
segments?: Segment[] | null;
|
|
114
|
+
}
|
|
115
|
+
export interface Statistics {
|
|
116
|
+
distinct_count?: number | null;
|
|
117
|
+
percent_null?: number | null;
|
|
118
|
+
min?: number | null;
|
|
119
|
+
max?: number | null;
|
|
120
|
+
avg?: number | null;
|
|
121
|
+
sd?: number | null;
|
|
122
|
+
q1?: number | null;
|
|
123
|
+
q3?: number | null;
|
|
124
|
+
earliest?: string | null;
|
|
125
|
+
latest?: string | null;
|
|
126
|
+
average_length?: number | null;
|
|
127
|
+
percent_email?: number | null;
|
|
128
|
+
percent_url?: number | null;
|
|
129
|
+
percent_state?: number | null;
|
|
130
|
+
percent_json?: number | null;
|
|
131
|
+
}
|
|
132
|
+
export interface FieldValues {
|
|
133
|
+
field_id?: string | null;
|
|
134
|
+
values?: unknown[] | null;
|
|
135
|
+
statistics?: Statistics | null;
|
|
136
|
+
}
|
|
137
|
+
export type Filter = {
|
|
138
|
+
segment_id: number;
|
|
139
|
+
} | {
|
|
140
|
+
field_id: string;
|
|
141
|
+
operation: string;
|
|
142
|
+
value?: unknown;
|
|
143
|
+
values?: unknown[];
|
|
144
|
+
bucket?: string;
|
|
145
|
+
};
|
|
146
|
+
export interface GroupBy {
|
|
147
|
+
field_id: string;
|
|
148
|
+
field_granularity?: string | null;
|
|
149
|
+
}
|
|
150
|
+
export interface FieldRef {
|
|
151
|
+
field_id: string;
|
|
152
|
+
bucket?: string;
|
|
153
|
+
}
|
|
154
|
+
export interface OrderBy {
|
|
155
|
+
field: FieldRef;
|
|
156
|
+
direction: "asc" | "desc";
|
|
157
|
+
}
|
|
158
|
+
export type Aggregation = {
|
|
159
|
+
function: "count";
|
|
160
|
+
sort_order?: "asc" | "desc" | null;
|
|
161
|
+
} | {
|
|
162
|
+
field_id: string;
|
|
163
|
+
function: "avg" | "count-distinct" | "max" | "min" | "sum";
|
|
164
|
+
sort_order?: "asc" | "desc" | null;
|
|
165
|
+
} | {
|
|
166
|
+
measure_id: number;
|
|
167
|
+
sort_order?: "asc" | "desc" | null;
|
|
168
|
+
};
|
|
169
|
+
export type ConstructQueryRequest = {
|
|
170
|
+
table_id: number;
|
|
171
|
+
filters?: Filter[] | null;
|
|
172
|
+
fields?: FieldRef[] | null;
|
|
173
|
+
aggregations?: Aggregation[] | null;
|
|
174
|
+
group_by?: GroupBy[] | null;
|
|
175
|
+
order_by?: OrderBy[] | null;
|
|
176
|
+
limit?: number | null;
|
|
177
|
+
} | {
|
|
178
|
+
metric_id: number;
|
|
179
|
+
filters?: Filter[] | null;
|
|
180
|
+
group_by?: GroupBy[] | null;
|
|
181
|
+
};
|
|
182
|
+
export interface ConstructQueryResponse {
|
|
183
|
+
query: string;
|
|
184
|
+
}
|
|
185
|
+
export interface ColumnMetadata {
|
|
186
|
+
name: string;
|
|
187
|
+
base_type: string;
|
|
188
|
+
display_name: string;
|
|
189
|
+
effective_type?: string | null;
|
|
190
|
+
}
|
|
191
|
+
export interface ExecuteQueryRequest {
|
|
192
|
+
query: string;
|
|
193
|
+
}
|
|
194
|
+
export interface ExecuteQueryResponse {
|
|
195
|
+
status: "completed" | "failed";
|
|
196
|
+
data?: {
|
|
197
|
+
cols: ColumnMetadata[];
|
|
198
|
+
rows: unknown[][];
|
|
199
|
+
};
|
|
200
|
+
row_count?: number;
|
|
201
|
+
running_time?: number;
|
|
202
|
+
error?: string;
|
|
203
|
+
}
|