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 ADDED
@@ -0,0 +1,4 @@
1
+ node_modules
2
+ dist
3
+ .git
4
+ *.md
package/.env.example ADDED
@@ -0,0 +1,5 @@
1
+ # Base URL of your Metabase instance (e.g. https://metabase.example.com)
2
+ METABASE_URL=
3
+
4
+ # API key created in Admin > Settings > Authentication > API Keys
5
+ METABASE_API_KEY=
package/.prettierrc ADDED
@@ -0,0 +1,5 @@
1
+ {
2
+ "trailingComma": "all",
3
+ "semi": true,
4
+ "singleQuote": false
5
+ }
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
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
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
+ }