@hypequery/mcp 0.1.0 → 0.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.
- package/README.md +25 -15
- package/dist/bin.d.ts +2 -2
- package/dist/bin.js +9 -9
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/prompts/dataset-guide.d.ts.map +1 -1
- package/dist/prompts/dataset-guide.js +7 -3
- package/dist/server.d.ts +7 -3
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +38 -6
- package/dist/tools/args.d.ts +137 -0
- package/dist/tools/args.d.ts.map +1 -0
- package/dist/tools/args.js +50 -0
- package/dist/tools/introspect.d.ts +2 -2
- package/dist/tools/introspect.d.ts.map +1 -1
- package/dist/tools/introspect.js +119 -23
- package/dist/tools/list-datasets.d.ts.map +1 -1
- package/dist/tools/list-datasets.js +16 -0
- package/dist/tools/query-dataset.d.ts +4 -4
- package/dist/tools/query-dataset.d.ts.map +1 -1
- package/dist/tools/query-dataset.js +17 -19
- package/dist/tools/query-metric.d.ts +3 -3
- package/dist/tools/query-metric.d.ts.map +1 -1
- package/dist/tools/query-metric.js +12 -11
- package/dist/types.d.ts +52 -5
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -24,7 +24,7 @@ pnpm add @hypequery/mcp
|
|
|
24
24
|
Create `mcp-config.ts`:
|
|
25
25
|
|
|
26
26
|
```typescript
|
|
27
|
-
import {
|
|
27
|
+
import { createDatasetClient } from '@hypequery/datasets';
|
|
28
28
|
import { createQueryBuilder } from '@hypequery/clickhouse';
|
|
29
29
|
import { OrdersDataset, CustomersDataset } from './datasets/index.js';
|
|
30
30
|
|
|
@@ -45,14 +45,15 @@ export const datasets = {
|
|
|
45
45
|
},
|
|
46
46
|
};
|
|
47
47
|
|
|
48
|
-
// Export
|
|
49
|
-
const
|
|
50
|
-
|
|
48
|
+
// Export the semantic runner consumed by the MCP server
|
|
49
|
+
const db = createQueryBuilder({
|
|
50
|
+
url: process.env.CLICKHOUSE_URL,
|
|
51
51
|
username: process.env.CLICKHOUSE_USER,
|
|
52
52
|
password: process.env.CLICKHOUSE_PASSWORD,
|
|
53
|
+
database: process.env.CLICKHOUSE_DATABASE,
|
|
53
54
|
});
|
|
54
55
|
|
|
55
|
-
export const
|
|
56
|
+
export const analytics = createDatasetClient({ queryBuilder: db });
|
|
56
57
|
```
|
|
57
58
|
|
|
58
59
|
### 2. Run the MCP Server
|
|
@@ -107,6 +108,7 @@ Lists all available datasets with their descriptions.
|
|
|
107
108
|
"name": "orders",
|
|
108
109
|
"description": "Customer orders and revenue data",
|
|
109
110
|
"dimensionCount": 5,
|
|
111
|
+
"measureCount": 4,
|
|
110
112
|
"metricCount": 4
|
|
111
113
|
}
|
|
112
114
|
],
|
|
@@ -136,8 +138,12 @@ Gets the complete schema for a dataset.
|
|
|
136
138
|
"region": { "type": "string", "label": "Region" },
|
|
137
139
|
"status": { "type": "string", "label": "Order Status" }
|
|
138
140
|
},
|
|
141
|
+
"measures": {
|
|
142
|
+
"revenue": { "aggregation": "sum", "field": "amount", "label": "Revenue" },
|
|
143
|
+
"orderCount": { "aggregation": "count", "field": "id", "label": "Order Count" }
|
|
144
|
+
},
|
|
139
145
|
"metrics": {
|
|
140
|
-
"
|
|
146
|
+
"totalRevenue": { "type": "metric", "aggregation": "revenue", "label": "Total Revenue" }
|
|
141
147
|
}
|
|
142
148
|
}
|
|
143
149
|
```
|
|
@@ -183,7 +189,7 @@ Executes a pre-defined metric query.
|
|
|
183
189
|
|
|
184
190
|
### `query_dataset`
|
|
185
191
|
|
|
186
|
-
Executes an ad-hoc dataset query with custom dimensions and
|
|
192
|
+
Executes an ad-hoc dataset query with custom dimensions and measures.
|
|
187
193
|
|
|
188
194
|
**Example:**
|
|
189
195
|
```typescript
|
|
@@ -192,7 +198,7 @@ Executes an ad-hoc dataset query with custom dimensions and metrics.
|
|
|
192
198
|
"arguments": {
|
|
193
199
|
"dataset": "orders",
|
|
194
200
|
"dimensions": ["region", "status"],
|
|
195
|
-
"
|
|
201
|
+
"measures": ["revenue", "orderCount"],
|
|
196
202
|
"limit": 100
|
|
197
203
|
}
|
|
198
204
|
}
|
|
@@ -204,15 +210,19 @@ You can also use the MCP server programmatically in your application:
|
|
|
204
210
|
|
|
205
211
|
```typescript
|
|
206
212
|
import { createMCPServer } from '@hypequery/mcp';
|
|
207
|
-
import {
|
|
213
|
+
import { createDatasetClient } from '@hypequery/datasets';
|
|
208
214
|
import { datasets } from './datasets/index.js';
|
|
209
|
-
import { queryBuilder } from './db/index.js';
|
|
210
215
|
|
|
211
|
-
const
|
|
216
|
+
const analytics = createDatasetClient({
|
|
217
|
+
url: process.env.CLICKHOUSE_URL,
|
|
218
|
+
username: process.env.CLICKHOUSE_USER,
|
|
219
|
+
password: process.env.CLICKHOUSE_PASSWORD,
|
|
220
|
+
database: process.env.CLICKHOUSE_DATABASE,
|
|
221
|
+
});
|
|
212
222
|
|
|
213
223
|
const server = await createMCPServer({
|
|
214
224
|
datasets,
|
|
215
|
-
|
|
225
|
+
analytics,
|
|
216
226
|
name: 'my-analytics-mcp',
|
|
217
227
|
version: '1.0.0',
|
|
218
228
|
});
|
|
@@ -250,8 +260,8 @@ The MCP server also exposes a `dataset_guide` prompt that provides natural langu
|
|
|
250
260
|
Your config file can use environment variables for database credentials:
|
|
251
261
|
|
|
252
262
|
```typescript
|
|
253
|
-
const
|
|
254
|
-
|
|
263
|
+
const analytics = createDatasetClient({
|
|
264
|
+
url: process.env.CLICKHOUSE_URL || 'http://localhost:8123',
|
|
255
265
|
username: process.env.CLICKHOUSE_USER || 'default',
|
|
256
266
|
password: process.env.CLICKHOUSE_PASSWORD,
|
|
257
267
|
database: process.env.CLICKHOUSE_DATABASE || 'default',
|
|
@@ -263,7 +273,7 @@ const queryBuilder = createQueryBuilder({
|
|
|
263
273
|
### MCP server not connecting
|
|
264
274
|
|
|
265
275
|
1. Check that the config file path is absolute, not relative
|
|
266
|
-
2. Ensure the config file exports both `datasets` and `
|
|
276
|
+
2. Ensure the config file exports both `datasets` and `analytics`
|
|
267
277
|
3. Check Claude Desktop logs for errors
|
|
268
278
|
|
|
269
279
|
### Queries failing
|
package/dist/bin.d.ts
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
* MCP Server CLI
|
|
4
4
|
*
|
|
5
5
|
* This is a standalone executable that starts the MCP server.
|
|
6
|
-
* Users can configure it by creating a config file that exports datasets and
|
|
6
|
+
* Users can configure it by creating a config file that exports datasets and analytics.
|
|
7
7
|
*
|
|
8
8
|
* Usage:
|
|
9
|
-
* npx hypequery-mcp --config ./mcp-config.
|
|
9
|
+
* npx hypequery-mcp --config ./mcp-config.mjs
|
|
10
10
|
*/
|
|
11
11
|
export {};
|
|
12
12
|
//# sourceMappingURL=bin.d.ts.map
|
package/dist/bin.js
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
* MCP Server CLI
|
|
4
4
|
*
|
|
5
5
|
* This is a standalone executable that starts the MCP server.
|
|
6
|
-
* Users can configure it by creating a config file that exports datasets and
|
|
6
|
+
* Users can configure it by creating a config file that exports datasets and analytics.
|
|
7
7
|
*
|
|
8
8
|
* Usage:
|
|
9
|
-
* npx hypequery-mcp --config ./mcp-config.
|
|
9
|
+
* npx hypequery-mcp --config ./mcp-config.mjs
|
|
10
10
|
*/
|
|
11
11
|
import { createMCPServer } from './server.js';
|
|
12
12
|
import { pathToFileURL } from 'url';
|
|
@@ -29,29 +29,29 @@ async function main() {
|
|
|
29
29
|
if (configIndex === -1 || !args[configIndex + 1]) {
|
|
30
30
|
console.error('Error: --config flag is required');
|
|
31
31
|
console.error('');
|
|
32
|
-
console.error('Usage: hypequery-mcp --config ./mcp-config.
|
|
32
|
+
console.error('Usage: hypequery-mcp --config ./mcp-config.mjs');
|
|
33
33
|
console.error('');
|
|
34
|
-
console.error('The config file should export { datasets,
|
|
34
|
+
console.error('The config file should export { datasets, analytics }:');
|
|
35
35
|
console.error('');
|
|
36
36
|
console.error(' export const datasets = { ... };');
|
|
37
|
-
console.error(' export const
|
|
37
|
+
console.error(' export const analytics = createDatasetClient({ ... });');
|
|
38
38
|
process.exit(1);
|
|
39
39
|
}
|
|
40
40
|
const configPath = resolve(process.cwd(), args[configIndex + 1]);
|
|
41
41
|
try {
|
|
42
42
|
// Dynamic import of the config file
|
|
43
43
|
const configModule = await import(pathToFileURL(configPath).href);
|
|
44
|
-
const { datasets,
|
|
44
|
+
const { datasets, analytics } = configModule;
|
|
45
45
|
if (!datasets) {
|
|
46
46
|
throw new Error('Config file must export "datasets"');
|
|
47
47
|
}
|
|
48
|
-
if (!
|
|
49
|
-
throw new Error('Config file must export "
|
|
48
|
+
if (!analytics) {
|
|
49
|
+
throw new Error('Config file must export "analytics"');
|
|
50
50
|
}
|
|
51
51
|
// Create and start the MCP server
|
|
52
52
|
await createMCPServer({
|
|
53
53
|
datasets,
|
|
54
|
-
|
|
54
|
+
analytics,
|
|
55
55
|
name: 'hypequery-mcp-server',
|
|
56
56
|
version: '0.1.0',
|
|
57
57
|
});
|
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,6 @@ export { getDatasetSchemaTool } from './tools/introspect.js';
|
|
|
10
10
|
export { queryMetricTool } from './tools/query-metric.js';
|
|
11
11
|
export { queryDatasetTool } from './tools/query-dataset.js';
|
|
12
12
|
export { datasetGuidePrompt } from './prompts/dataset-guide.js';
|
|
13
|
-
export type { DatasetRegistry, QueryMetricArgs, QueryDatasetArgs, GetDatasetSchemaArgs, MCPToolResponse, DatasetSchema, DimensionSchema, MetricSchema, RelationshipSchema, DatasetListItem, DatasetsListResponse, QueryResultResponse, QueryResultMeta, } from './types.js';
|
|
13
|
+
export type { DatasetRegistry, QueryMetricArgs, QueryDatasetArgs, QueryToolOptions, GetDatasetSchemaArgs, MCPToolResponse, DatasetSchema, DimensionSchema, MetricSchema, RelationshipSchema, DatasetListItem, DatasetsListResponse, QueryResultResponse, QueryResultMeta, } from './types.js';
|
|
14
14
|
export { MAX_QUERY_LIMIT, DEFAULT_QUERY_LIMIT } from './types.js';
|
|
15
15
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AACxF,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAGhE,YAAY,EACV,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,oBAAoB,EACpB,eAAe,EACf,aAAa,EACb,eAAe,EACf,YAAY,EACZ,kBAAkB,EAClB,eAAe,EACf,oBAAoB,EACpB,mBAAmB,EACnB,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AACxF,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAGhE,YAAY,EACV,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,EACpB,eAAe,EACf,aAAa,EACb,eAAe,EACf,YAAY,EACZ,kBAAkB,EAClB,eAAe,EACf,oBAAoB,EACpB,mBAAmB,EACnB,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dataset-guide.d.ts","sourceRoot":"","sources":["../../src/prompts/dataset-guide.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,eAAe,EAAE,WAAW,CAAC,EAAE,MAAM;;;;;;;;
|
|
1
|
+
{"version":3,"file":"dataset-guide.d.ts","sourceRoot":"","sources":["../../src/prompts/dataset-guide.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,eAAe,EAAE,WAAW,CAAC,EAAE,MAAM;;;;;;;;EAuIjF"}
|
|
@@ -12,12 +12,16 @@ export function datasetGuidePrompt(datasets, datasetName) {
|
|
|
12
12
|
const datasetAny = dataset;
|
|
13
13
|
// Generate dataset-specific guide
|
|
14
14
|
const dimensions = datasetAny.dimensions ? Object.keys(datasetAny.dimensions) : [];
|
|
15
|
+
const measures = datasetAny.measures ? Object.keys(datasetAny.measures) : [];
|
|
15
16
|
const metrics = datasetAny.metrics ? Object.keys(datasetAny.metrics) : [];
|
|
16
17
|
const guide = `# Querying the ${datasetName} dataset
|
|
17
18
|
|
|
18
19
|
## Available Dimensions
|
|
19
20
|
${dimensions.map((d) => `- ${d}`).join('\n')}
|
|
20
21
|
|
|
22
|
+
## Available Measures
|
|
23
|
+
${measures.map((m) => `- ${m}`).join('\n')}
|
|
24
|
+
|
|
21
25
|
## Available Metrics
|
|
22
26
|
${metrics.map((m) => `- ${m}`).join('\n')}
|
|
23
27
|
|
|
@@ -46,7 +50,7 @@ Show "${metrics[0] || 'revenue'}" by month for the last year
|
|
|
46
50
|
## Tips
|
|
47
51
|
- Use natural language to describe what you want to see
|
|
48
52
|
- The system will translate your query into the appropriate dataset query
|
|
49
|
-
- You can filter, group, and aggregate data using the available dimensions and metrics
|
|
53
|
+
- You can filter, group, and aggregate data using the available dimensions, measures, and metrics
|
|
50
54
|
`;
|
|
51
55
|
return {
|
|
52
56
|
messages: [
|
|
@@ -70,9 +74,9 @@ ${datasetList.map((name) => `- ${name}`).join('\n')}
|
|
|
70
74
|
## How to Query
|
|
71
75
|
|
|
72
76
|
1. **List datasets**: Use the \`list_datasets\` tool to see all available datasets
|
|
73
|
-
2. **Get schema**: Use the \`get_dataset_schema\` tool to see dimensions and metrics for a dataset
|
|
77
|
+
2. **Get schema**: Use the \`get_dataset_schema\` tool to see dimensions, measures, and metrics for a dataset
|
|
74
78
|
3. **Query metric**: Use the \`query_metric\` tool to execute a pre-defined metric
|
|
75
|
-
4. **Query dataset**: Use the \`query_dataset\` tool for ad-hoc queries with custom dimensions and
|
|
79
|
+
4. **Query dataset**: Use the \`query_dataset\` tool for ad-hoc queries with custom dimensions and measures
|
|
76
80
|
|
|
77
81
|
## Example Workflow
|
|
78
82
|
|
package/dist/server.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Exposes datasets and metrics via Model Context Protocol (MCP)
|
|
5
5
|
* for use with Claude Desktop, Cursor, and other MCP-compatible tools.
|
|
6
6
|
*/
|
|
7
|
-
import type {
|
|
7
|
+
import type { DatasetClient } from '@hypequery/datasets';
|
|
8
8
|
import type { DatasetRegistry } from './types.js';
|
|
9
9
|
export interface MCPServerConfig {
|
|
10
10
|
/**
|
|
@@ -12,9 +12,9 @@ export interface MCPServerConfig {
|
|
|
12
12
|
*/
|
|
13
13
|
datasets: DatasetRegistry;
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
15
|
+
* Semantic analytics for running metric and dataset queries
|
|
16
16
|
*/
|
|
17
|
-
|
|
17
|
+
analytics: DatasetClient;
|
|
18
18
|
/**
|
|
19
19
|
* Server name (shown in MCP client)
|
|
20
20
|
*/
|
|
@@ -23,6 +23,10 @@ export interface MCPServerConfig {
|
|
|
23
23
|
* Server version
|
|
24
24
|
*/
|
|
25
25
|
version?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Trusted tenant id used to scope tenant-keyed datasets.
|
|
28
|
+
*/
|
|
29
|
+
tenantId?: string;
|
|
26
30
|
}
|
|
27
31
|
export declare class HypequeryMCPServer {
|
|
28
32
|
private server;
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAUH,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAUH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAMzD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,QAAQ,EAAE,eAAe,CAAC;IAE1B;;OAEG;IACH,SAAS,EAAE,aAAa,CAAC;IAEzB;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAiCD,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAkB;gBAEpB,MAAM,EAAE,eAAe;IAoBnC,OAAO,CAAC,aAAa;IAuOrB;;OAEG;IACG,KAAK;IAQX;;OAEG;IACG,IAAI;CAGX;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAI1F"}
|
package/dist/server.js
CHANGED
|
@@ -12,10 +12,34 @@ import { getDatasetSchemaTool } from './tools/introspect.js';
|
|
|
12
12
|
import { queryMetricTool } from './tools/query-metric.js';
|
|
13
13
|
import { queryDatasetTool } from './tools/query-dataset.js';
|
|
14
14
|
import { datasetGuidePrompt } from './prompts/dataset-guide.js';
|
|
15
|
+
function isRecord(value) {
|
|
16
|
+
return !!value && typeof value === 'object';
|
|
17
|
+
}
|
|
18
|
+
function getTenantKey(dataset) {
|
|
19
|
+
if (!isRecord(dataset)) {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
const config = dataset.config;
|
|
23
|
+
const configTenantKey = isRecord(config) ? config.tenantKey : undefined;
|
|
24
|
+
const tenantKey = dataset.tenantKey ?? configTenantKey;
|
|
25
|
+
return typeof tenantKey === 'string' && tenantKey.length > 0 ? tenantKey : undefined;
|
|
26
|
+
}
|
|
27
|
+
function validateTenantConfig(config) {
|
|
28
|
+
if (config.tenantId) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const tenantScopedDatasets = Object.entries(config.datasets ?? {})
|
|
32
|
+
.filter(([, ds]) => getTenantKey(ds))
|
|
33
|
+
.map(([name]) => name);
|
|
34
|
+
if (tenantScopedDatasets.length > 0) {
|
|
35
|
+
throw new Error(`MCP server tenantId is required for tenant-scoped datasets: ${tenantScopedDatasets.join(', ')}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
15
38
|
export class HypequeryMCPServer {
|
|
16
39
|
server;
|
|
17
40
|
config;
|
|
18
41
|
constructor(config) {
|
|
42
|
+
validateTenantConfig(config);
|
|
19
43
|
this.config = config;
|
|
20
44
|
this.server = new Server({
|
|
21
45
|
name: config.name ?? 'hypequery-mcp-server',
|
|
@@ -42,7 +66,7 @@ export class HypequeryMCPServer {
|
|
|
42
66
|
},
|
|
43
67
|
{
|
|
44
68
|
name: 'get_dataset_schema',
|
|
45
|
-
description: 'Get the schema (dimensions, metrics, relationships) for a specific dataset',
|
|
69
|
+
description: 'Get the schema (dimensions, measures, named metrics, filters, relationships) for a specific dataset',
|
|
46
70
|
inputSchema: {
|
|
47
71
|
type: 'object',
|
|
48
72
|
properties: {
|
|
@@ -110,13 +134,17 @@ export class HypequeryMCPServer {
|
|
|
110
134
|
type: 'number',
|
|
111
135
|
description: 'Maximum number of rows to return (optional)',
|
|
112
136
|
},
|
|
137
|
+
offset: {
|
|
138
|
+
type: 'number',
|
|
139
|
+
description: 'Number of rows to skip before returning results (optional)',
|
|
140
|
+
},
|
|
113
141
|
},
|
|
114
142
|
required: ['dataset', 'metric'],
|
|
115
143
|
},
|
|
116
144
|
},
|
|
117
145
|
{
|
|
118
146
|
name: 'query_dataset',
|
|
119
|
-
description: 'Execute an ad-hoc dataset query with custom dimensions and
|
|
147
|
+
description: 'Execute an ad-hoc dataset query with custom dimensions and measures',
|
|
120
148
|
inputSchema: {
|
|
121
149
|
type: 'object',
|
|
122
150
|
properties: {
|
|
@@ -129,10 +157,10 @@ export class HypequeryMCPServer {
|
|
|
129
157
|
items: { type: 'string' },
|
|
130
158
|
description: 'Dimensions to select',
|
|
131
159
|
},
|
|
132
|
-
|
|
160
|
+
measures: {
|
|
133
161
|
type: 'array',
|
|
134
162
|
items: { type: 'string' },
|
|
135
|
-
description: '
|
|
163
|
+
description: 'Measures to calculate',
|
|
136
164
|
},
|
|
137
165
|
filters: {
|
|
138
166
|
type: 'array',
|
|
@@ -171,6 +199,10 @@ export class HypequeryMCPServer {
|
|
|
171
199
|
type: 'number',
|
|
172
200
|
description: 'Maximum number of rows to return (optional)',
|
|
173
201
|
},
|
|
202
|
+
offset: {
|
|
203
|
+
type: 'number',
|
|
204
|
+
description: 'Number of rows to skip before returning results (optional)',
|
|
205
|
+
},
|
|
174
206
|
},
|
|
175
207
|
required: ['dataset'],
|
|
176
208
|
},
|
|
@@ -187,9 +219,9 @@ export class HypequeryMCPServer {
|
|
|
187
219
|
case 'get_dataset_schema':
|
|
188
220
|
return await getDatasetSchemaTool(this.config.datasets, args);
|
|
189
221
|
case 'query_metric':
|
|
190
|
-
return await queryMetricTool(this.config.datasets, this.config.
|
|
222
|
+
return await queryMetricTool(this.config.datasets, this.config.analytics, args, { tenantId: this.config.tenantId });
|
|
191
223
|
case 'query_dataset':
|
|
192
|
-
return await queryDatasetTool(this.config.datasets, this.config.
|
|
224
|
+
return await queryDatasetTool(this.config.datasets, this.config.analytics, args, { tenantId: this.config.tenantId });
|
|
193
225
|
default:
|
|
194
226
|
throw new Error(`Unknown tool: ${name}`);
|
|
195
227
|
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { type MetricFilter } from '@hypequery/datasets';
|
|
3
|
+
export declare const queryMetricArgsSchema: z.ZodObject<{
|
|
4
|
+
dimensions: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
5
|
+
filters: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
6
|
+
field: z.ZodString;
|
|
7
|
+
operator: z.ZodEnum<["eq", "neq", "gt", "gte", "lt", "lte", "in", "notIn", "between", "like"]>;
|
|
8
|
+
value: z.ZodEffects<z.ZodAny, any, any>;
|
|
9
|
+
}, "strict", z.ZodTypeAny, {
|
|
10
|
+
operator: "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "notIn" | "between" | "like";
|
|
11
|
+
field: string;
|
|
12
|
+
value?: any;
|
|
13
|
+
}, {
|
|
14
|
+
operator: "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "notIn" | "between" | "like";
|
|
15
|
+
field: string;
|
|
16
|
+
value?: any;
|
|
17
|
+
}>, "many">>;
|
|
18
|
+
grain: z.ZodOptional<z.ZodEnum<["day", "week", "month", "quarter", "year"]>>;
|
|
19
|
+
orderBy: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
20
|
+
field: z.ZodString;
|
|
21
|
+
direction: z.ZodEnum<["asc", "desc"]>;
|
|
22
|
+
}, "strict", z.ZodTypeAny, {
|
|
23
|
+
field: string;
|
|
24
|
+
direction: "asc" | "desc";
|
|
25
|
+
}, {
|
|
26
|
+
field: string;
|
|
27
|
+
direction: "asc" | "desc";
|
|
28
|
+
}>, "many">>;
|
|
29
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
30
|
+
offset: z.ZodOptional<z.ZodNumber>;
|
|
31
|
+
} & {
|
|
32
|
+
dataset: z.ZodOptional<z.ZodString>;
|
|
33
|
+
metric: z.ZodOptional<z.ZodString>;
|
|
34
|
+
}, "strict", z.ZodTypeAny, {
|
|
35
|
+
dataset?: string | undefined;
|
|
36
|
+
metric?: string | undefined;
|
|
37
|
+
dimensions?: string[] | undefined;
|
|
38
|
+
filters?: {
|
|
39
|
+
operator: "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "notIn" | "between" | "like";
|
|
40
|
+
field: string;
|
|
41
|
+
value?: any;
|
|
42
|
+
}[] | undefined;
|
|
43
|
+
grain?: "day" | "week" | "month" | "quarter" | "year" | undefined;
|
|
44
|
+
orderBy?: {
|
|
45
|
+
field: string;
|
|
46
|
+
direction: "asc" | "desc";
|
|
47
|
+
}[] | undefined;
|
|
48
|
+
limit?: number | undefined;
|
|
49
|
+
offset?: number | undefined;
|
|
50
|
+
}, {
|
|
51
|
+
dataset?: string | undefined;
|
|
52
|
+
metric?: string | undefined;
|
|
53
|
+
dimensions?: string[] | undefined;
|
|
54
|
+
filters?: {
|
|
55
|
+
operator: "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "notIn" | "between" | "like";
|
|
56
|
+
field: string;
|
|
57
|
+
value?: any;
|
|
58
|
+
}[] | undefined;
|
|
59
|
+
grain?: "day" | "week" | "month" | "quarter" | "year" | undefined;
|
|
60
|
+
orderBy?: {
|
|
61
|
+
field: string;
|
|
62
|
+
direction: "asc" | "desc";
|
|
63
|
+
}[] | undefined;
|
|
64
|
+
limit?: number | undefined;
|
|
65
|
+
offset?: number | undefined;
|
|
66
|
+
}>;
|
|
67
|
+
export declare const queryDatasetArgsSchema: z.ZodObject<{
|
|
68
|
+
dimensions: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
69
|
+
filters: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
70
|
+
field: z.ZodString;
|
|
71
|
+
operator: z.ZodEnum<["eq", "neq", "gt", "gte", "lt", "lte", "in", "notIn", "between", "like"]>;
|
|
72
|
+
value: z.ZodEffects<z.ZodAny, any, any>;
|
|
73
|
+
}, "strict", z.ZodTypeAny, {
|
|
74
|
+
operator: "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "notIn" | "between" | "like";
|
|
75
|
+
field: string;
|
|
76
|
+
value?: any;
|
|
77
|
+
}, {
|
|
78
|
+
operator: "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "notIn" | "between" | "like";
|
|
79
|
+
field: string;
|
|
80
|
+
value?: any;
|
|
81
|
+
}>, "many">>;
|
|
82
|
+
grain: z.ZodOptional<z.ZodEnum<["day", "week", "month", "quarter", "year"]>>;
|
|
83
|
+
orderBy: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
84
|
+
field: z.ZodString;
|
|
85
|
+
direction: z.ZodEnum<["asc", "desc"]>;
|
|
86
|
+
}, "strict", z.ZodTypeAny, {
|
|
87
|
+
field: string;
|
|
88
|
+
direction: "asc" | "desc";
|
|
89
|
+
}, {
|
|
90
|
+
field: string;
|
|
91
|
+
direction: "asc" | "desc";
|
|
92
|
+
}>, "many">>;
|
|
93
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
94
|
+
offset: z.ZodOptional<z.ZodNumber>;
|
|
95
|
+
} & {
|
|
96
|
+
dataset: z.ZodOptional<z.ZodString>;
|
|
97
|
+
measures: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
98
|
+
}, "strict", z.ZodTypeAny, {
|
|
99
|
+
dataset?: string | undefined;
|
|
100
|
+
dimensions?: string[] | undefined;
|
|
101
|
+
filters?: {
|
|
102
|
+
operator: "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "notIn" | "between" | "like";
|
|
103
|
+
field: string;
|
|
104
|
+
value?: any;
|
|
105
|
+
}[] | undefined;
|
|
106
|
+
grain?: "day" | "week" | "month" | "quarter" | "year" | undefined;
|
|
107
|
+
orderBy?: {
|
|
108
|
+
field: string;
|
|
109
|
+
direction: "asc" | "desc";
|
|
110
|
+
}[] | undefined;
|
|
111
|
+
limit?: number | undefined;
|
|
112
|
+
offset?: number | undefined;
|
|
113
|
+
measures?: string[] | undefined;
|
|
114
|
+
}, {
|
|
115
|
+
dataset?: string | undefined;
|
|
116
|
+
dimensions?: string[] | undefined;
|
|
117
|
+
filters?: {
|
|
118
|
+
operator: "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "notIn" | "between" | "like";
|
|
119
|
+
field: string;
|
|
120
|
+
value?: any;
|
|
121
|
+
}[] | undefined;
|
|
122
|
+
grain?: "day" | "week" | "month" | "quarter" | "year" | undefined;
|
|
123
|
+
orderBy?: {
|
|
124
|
+
field: string;
|
|
125
|
+
direction: "asc" | "desc";
|
|
126
|
+
}[] | undefined;
|
|
127
|
+
limit?: number | undefined;
|
|
128
|
+
offset?: number | undefined;
|
|
129
|
+
measures?: string[] | undefined;
|
|
130
|
+
}>;
|
|
131
|
+
export declare function parseToolArgs<T>(schema: z.ZodType<T>, toolName: string, args: unknown): T;
|
|
132
|
+
export declare function toMetricFilters(filters?: Array<{
|
|
133
|
+
field: string;
|
|
134
|
+
operator: MetricFilter['operator'];
|
|
135
|
+
value?: unknown;
|
|
136
|
+
}>): MetricFilter[];
|
|
137
|
+
//# sourceMappingURL=args.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../../src/tools/args.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAA6B,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAuBnF,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGhC,CAAC;AAEH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGjC,CAAC;AAWH,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,CAAC,CAMzF;AAED,wBAAgB,eAAe,CAC7B,OAAO,GAAE,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,YAAY,CAAC,UAAU,CAAC,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,CAAM,GAC1F,YAAY,EAAE,CAMhB"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { SEMANTIC_FILTER_OPERATORS } from '@hypequery/datasets';
|
|
3
|
+
import { MAX_QUERY_LIMIT } from '../types.js';
|
|
4
|
+
const filterSchema = z.object({
|
|
5
|
+
field: z.string().min(1),
|
|
6
|
+
operator: z.enum(SEMANTIC_FILTER_OPERATORS),
|
|
7
|
+
value: z.any().refine(value => value !== undefined, 'Required'),
|
|
8
|
+
}).strict();
|
|
9
|
+
const orderBySchema = z.object({
|
|
10
|
+
field: z.string().min(1),
|
|
11
|
+
direction: z.enum(['asc', 'desc']),
|
|
12
|
+
}).strict();
|
|
13
|
+
const baseQuerySchema = z.object({
|
|
14
|
+
dimensions: z.array(z.string().min(1)).optional(),
|
|
15
|
+
filters: z.array(filterSchema).optional(),
|
|
16
|
+
grain: z.enum(['day', 'week', 'month', 'quarter', 'year']).optional(),
|
|
17
|
+
orderBy: z.array(orderBySchema).optional(),
|
|
18
|
+
limit: z.number().int().nonnegative().max(MAX_QUERY_LIMIT).optional(),
|
|
19
|
+
offset: z.number().int().nonnegative().optional(),
|
|
20
|
+
}).strict();
|
|
21
|
+
export const queryMetricArgsSchema = baseQuerySchema.extend({
|
|
22
|
+
dataset: z.string().min(1).optional(),
|
|
23
|
+
metric: z.string().min(1).optional(),
|
|
24
|
+
});
|
|
25
|
+
export const queryDatasetArgsSchema = baseQuerySchema.extend({
|
|
26
|
+
dataset: z.string().min(1).optional(),
|
|
27
|
+
measures: z.array(z.string().min(1)).optional(),
|
|
28
|
+
});
|
|
29
|
+
function formatZodError(error) {
|
|
30
|
+
return error.issues
|
|
31
|
+
.map(issue => {
|
|
32
|
+
const path = issue.path.length > 0 ? issue.path.join('.') : 'arguments';
|
|
33
|
+
return `${path}: ${issue.message}`;
|
|
34
|
+
})
|
|
35
|
+
.join('; ');
|
|
36
|
+
}
|
|
37
|
+
export function parseToolArgs(schema, toolName, args) {
|
|
38
|
+
const result = schema.safeParse(args);
|
|
39
|
+
if (!result.success) {
|
|
40
|
+
throw new Error(`Invalid ${toolName} arguments: ${formatZodError(result.error)}`);
|
|
41
|
+
}
|
|
42
|
+
return result.data;
|
|
43
|
+
}
|
|
44
|
+
export function toMetricFilters(filters = []) {
|
|
45
|
+
return filters.map(filter => ({
|
|
46
|
+
field: filter.field,
|
|
47
|
+
operator: filter.operator,
|
|
48
|
+
value: filter.value,
|
|
49
|
+
}));
|
|
50
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Get Dataset Schema Tool
|
|
3
3
|
*
|
|
4
|
-
* Returns the complete schema for a dataset including dimensions,
|
|
5
|
-
* and relationships.
|
|
4
|
+
* Returns the complete schema for a dataset including dimensions, measures,
|
|
5
|
+
* named metrics, filters, and relationships.
|
|
6
6
|
*/
|
|
7
7
|
import type { DatasetRegistry, MCPToolResponse } from '../types.js';
|
|
8
8
|
export declare function getDatasetSchemaTool(datasets: DatasetRegistry, args: unknown): Promise<MCPToolResponse>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"introspect.d.ts","sourceRoot":"","sources":["../../src/tools/introspect.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"introspect.d.ts","sourceRoot":"","sources":["../../src/tools/introspect.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EACV,eAAe,EAEf,eAAe,EAOhB,MAAM,aAAa,CAAC;AAMrB,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,eAAe,EACzB,IAAI,EAAE,OAAO,GACZ,OAAO,CAAC,eAAe,CAAC,CA+K1B"}
|
package/dist/tools/introspect.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Get Dataset Schema Tool
|
|
3
3
|
*
|
|
4
|
-
* Returns the complete schema for a dataset including dimensions,
|
|
5
|
-
* and relationships.
|
|
4
|
+
* Returns the complete schema for a dataset including dimensions, measures,
|
|
5
|
+
* named metrics, filters, and relationships.
|
|
6
6
|
*/
|
|
7
|
+
import { getDatasetCatalog } from '@hypequery/datasets';
|
|
8
|
+
function isDatasetInstance(value) {
|
|
9
|
+
return !!value && typeof value === 'object' && value.__type === 'dataset';
|
|
10
|
+
}
|
|
7
11
|
export async function getDatasetSchemaTool(datasets, args) {
|
|
8
12
|
// Parse and validate args
|
|
9
13
|
const validatedArgs = args;
|
|
@@ -15,7 +19,6 @@ export async function getDatasetSchemaTool(datasets, args) {
|
|
|
15
19
|
if (!dataset) {
|
|
16
20
|
throw new Error(`Dataset not found: ${datasetName}`);
|
|
17
21
|
}
|
|
18
|
-
// Build schema response with proper types
|
|
19
22
|
const datasetAny = dataset;
|
|
20
23
|
const schema = {
|
|
21
24
|
name: datasetName,
|
|
@@ -24,24 +27,129 @@ export async function getDatasetSchemaTool(datasets, args) {
|
|
|
24
27
|
timeKey: datasetAny.timeKey || datasetAny.config?.timeKey || null,
|
|
25
28
|
tenantKey: datasetAny.tenantKey || datasetAny.config?.tenantKey || null,
|
|
26
29
|
dimensions: {},
|
|
30
|
+
measures: {},
|
|
27
31
|
metrics: {},
|
|
32
|
+
filters: {},
|
|
28
33
|
relationships: {},
|
|
34
|
+
limits: datasetAny.limits,
|
|
29
35
|
};
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
36
|
+
if (isDatasetInstance(dataset)) {
|
|
37
|
+
const catalog = getDatasetCatalog(dataset);
|
|
38
|
+
schema.source = catalog.source;
|
|
39
|
+
schema.timeKey = catalog.timeKey ?? null;
|
|
40
|
+
schema.tenantKey = catalog.tenantKey ?? null;
|
|
41
|
+
schema.limits = catalog.limits;
|
|
42
|
+
for (const [name, dimension] of Object.entries(catalog.dimensions)) {
|
|
33
43
|
const dimSchema = {
|
|
34
|
-
type: dimension.
|
|
35
|
-
column: dimension.column
|
|
44
|
+
type: dimension.type,
|
|
45
|
+
column: dimension.column ?? name,
|
|
46
|
+
sql: dimension.sql ?? null,
|
|
36
47
|
label: dimension.label || name,
|
|
37
48
|
description: dimension.description || '',
|
|
38
|
-
examples:
|
|
49
|
+
examples: [],
|
|
50
|
+
filterable: dimension.filterable,
|
|
51
|
+
groupable: dimension.groupable,
|
|
39
52
|
};
|
|
40
53
|
schema.dimensions[name] = dimSchema;
|
|
41
54
|
}
|
|
55
|
+
for (const [name, measure] of Object.entries(catalog.measures)) {
|
|
56
|
+
const measureSchema = {
|
|
57
|
+
aggregation: measure.aggregation,
|
|
58
|
+
field: measure.field,
|
|
59
|
+
sql: measure.sql ?? null,
|
|
60
|
+
label: measure.label || name,
|
|
61
|
+
description: measure.description || '',
|
|
62
|
+
};
|
|
63
|
+
schema.measures[name] = measureSchema;
|
|
64
|
+
}
|
|
65
|
+
for (const [name, filter] of Object.entries(catalog.filters)) {
|
|
66
|
+
const filterSchema = {
|
|
67
|
+
field: filter.field,
|
|
68
|
+
label: filter.label || name,
|
|
69
|
+
description: filter.description || '',
|
|
70
|
+
operators: filter.operators ? [...filter.operators] : null,
|
|
71
|
+
};
|
|
72
|
+
schema.filters[name] = filterSchema;
|
|
73
|
+
}
|
|
74
|
+
for (const [name, metric] of Object.entries(catalog.metrics)) {
|
|
75
|
+
const metSchema = {
|
|
76
|
+
type: metric.kind,
|
|
77
|
+
aggregation: metric.measures?.join(', ') || '',
|
|
78
|
+
label: metric.label || name,
|
|
79
|
+
description: metric.description || '',
|
|
80
|
+
format: null,
|
|
81
|
+
};
|
|
82
|
+
schema.metrics[name] = metSchema;
|
|
83
|
+
}
|
|
84
|
+
for (const [name, relationship] of Object.entries(catalog.relationships)) {
|
|
85
|
+
const relSchema = {
|
|
86
|
+
type: relationship.kind,
|
|
87
|
+
target: relationship.target,
|
|
88
|
+
from: relationship.from,
|
|
89
|
+
to: relationship.to,
|
|
90
|
+
execution: relationship.execution,
|
|
91
|
+
description: '',
|
|
92
|
+
};
|
|
93
|
+
schema.relationships[name] = relSchema;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
// Legacy object-shaped fixtures/configs.
|
|
98
|
+
if (datasetAny.dimensions) {
|
|
99
|
+
for (const [name, dimension] of Object.entries(datasetAny.dimensions)) {
|
|
100
|
+
const dimSchema = {
|
|
101
|
+
type: dimension.fieldType || dimension.type || 'unknown',
|
|
102
|
+
column: dimension.column || name,
|
|
103
|
+
sql: dimension.sql || null,
|
|
104
|
+
label: dimension.label || name,
|
|
105
|
+
description: dimension.description || '',
|
|
106
|
+
examples: dimension.examples || [],
|
|
107
|
+
filterable: dimension.filterable !== false,
|
|
108
|
+
groupable: dimension.groupable !== false,
|
|
109
|
+
};
|
|
110
|
+
schema.dimensions[name] = dimSchema;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (datasetAny.measures) {
|
|
114
|
+
for (const [name, measure] of Object.entries(datasetAny.measures)) {
|
|
115
|
+
const measureSchema = {
|
|
116
|
+
aggregation: measure.aggregation || measure.type || 'unknown',
|
|
117
|
+
field: measure.field || name,
|
|
118
|
+
sql: measure.sql || null,
|
|
119
|
+
label: measure.label || name,
|
|
120
|
+
description: measure.description || '',
|
|
121
|
+
};
|
|
122
|
+
schema.measures[name] = measureSchema;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (datasetAny.filters) {
|
|
126
|
+
for (const [name, filter] of Object.entries(datasetAny.filters)) {
|
|
127
|
+
const filterSchema = {
|
|
128
|
+
field: filter.field || name,
|
|
129
|
+
label: filter.label || name,
|
|
130
|
+
description: filter.description || '',
|
|
131
|
+
operators: filter.operators || null,
|
|
132
|
+
};
|
|
133
|
+
schema.filters[name] = filterSchema;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (datasetAny.relationships) {
|
|
137
|
+
for (const [name, relationship] of Object.entries(datasetAny.relationships)) {
|
|
138
|
+
const rel = relationship;
|
|
139
|
+
const relSchema = {
|
|
140
|
+
type: rel.type || rel.kind || 'unknown',
|
|
141
|
+
target: typeof rel.target === 'function' ? rel.target()?.name || '' : rel.target || rel.dataset?.name || '',
|
|
142
|
+
from: rel.from,
|
|
143
|
+
to: rel.to,
|
|
144
|
+
execution: rel.execution,
|
|
145
|
+
description: rel.description || '',
|
|
146
|
+
};
|
|
147
|
+
schema.relationships[name] = relSchema;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
42
150
|
}
|
|
43
|
-
//
|
|
44
|
-
if (datasetAny.metrics) {
|
|
151
|
+
// Backward compatibility for legacy object-shaped dataset fixtures.
|
|
152
|
+
if (!isDatasetInstance(dataset) && datasetAny.metrics) {
|
|
45
153
|
for (const [name, metric] of Object.entries(datasetAny.metrics)) {
|
|
46
154
|
const metSchema = {
|
|
47
155
|
type: metric.spec?.__type || metric.type || 'unknown',
|
|
@@ -53,18 +161,6 @@ export async function getDatasetSchemaTool(datasets, args) {
|
|
|
53
161
|
schema.metrics[name] = metSchema;
|
|
54
162
|
}
|
|
55
163
|
}
|
|
56
|
-
// Extract relationships with proper typing
|
|
57
|
-
if (datasetAny.relationships) {
|
|
58
|
-
for (const [name, relationship] of Object.entries(datasetAny.relationships)) {
|
|
59
|
-
const rel = relationship;
|
|
60
|
-
const relSchema = {
|
|
61
|
-
type: rel.type || rel.kind || 'unknown',
|
|
62
|
-
target: typeof rel.target === 'function' ? rel.target()?.name || '' : rel.target || rel.dataset?.name || '',
|
|
63
|
-
description: rel.description || '',
|
|
64
|
-
};
|
|
65
|
-
schema.relationships[name] = relSchema;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
164
|
return {
|
|
69
165
|
content: [
|
|
70
166
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-datasets.d.ts","sourceRoot":"","sources":["../../src/tools/list-datasets.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"list-datasets.d.ts","sourceRoot":"","sources":["../../src/tools/list-datasets.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAyC,MAAM,aAAa,CAAC;AAM3G,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,CA2C1F"}
|
|
@@ -3,17 +3,33 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Returns a list of all available datasets with their descriptions.
|
|
5
5
|
*/
|
|
6
|
+
import { getDatasetCatalog } from '@hypequery/datasets';
|
|
7
|
+
function isDatasetInstance(value) {
|
|
8
|
+
return !!value && typeof value === 'object' && value.__type === 'dataset';
|
|
9
|
+
}
|
|
6
10
|
export async function listDatasetsTool(datasets) {
|
|
7
11
|
const datasetList = Object.entries(datasets).map(([name, dataset]) => {
|
|
8
12
|
const datasetAny = dataset;
|
|
9
13
|
// Try to extract description from dataset instance
|
|
10
14
|
const description = datasetAny.description || datasetAny.config?.description || 'No description available';
|
|
15
|
+
if (isDatasetInstance(dataset)) {
|
|
16
|
+
const catalog = getDatasetCatalog(dataset);
|
|
17
|
+
return {
|
|
18
|
+
name,
|
|
19
|
+
description,
|
|
20
|
+
dimensionCount: Object.keys(catalog.dimensions).length,
|
|
21
|
+
measureCount: Object.keys(catalog.measures).length,
|
|
22
|
+
metricCount: Object.keys(catalog.metrics).length,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
11
25
|
const dimensionCount = datasetAny.dimensions ? Object.keys(datasetAny.dimensions).length : 0;
|
|
26
|
+
const measureCount = datasetAny.measures ? Object.keys(datasetAny.measures).length : 0;
|
|
12
27
|
const metricCount = datasetAny.metrics ? Object.keys(datasetAny.metrics).length : 0;
|
|
13
28
|
return {
|
|
14
29
|
name,
|
|
15
30
|
description,
|
|
16
31
|
dimensionCount,
|
|
32
|
+
measureCount,
|
|
17
33
|
metricCount,
|
|
18
34
|
};
|
|
19
35
|
});
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Query Dataset Tool
|
|
3
3
|
*
|
|
4
|
-
* Executes an ad-hoc dataset query with custom dimensions and
|
|
4
|
+
* Executes an ad-hoc dataset query with custom dimensions and measures.
|
|
5
5
|
*/
|
|
6
|
-
import type {
|
|
7
|
-
import type { DatasetRegistry, MCPToolResponse } from '../types.js';
|
|
8
|
-
export declare function queryDatasetTool(datasets: DatasetRegistry,
|
|
6
|
+
import type { DatasetClient } from '@hypequery/datasets';
|
|
7
|
+
import type { DatasetRegistry, MCPToolResponse, QueryToolOptions } from '../types.js';
|
|
8
|
+
export declare function queryDatasetTool(datasets: DatasetRegistry, analytics: DatasetClient, args: unknown, options?: QueryToolOptions): Promise<MCPToolResponse>;
|
|
9
9
|
//# sourceMappingURL=query-dataset.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query-dataset.d.ts","sourceRoot":"","sources":["../../src/tools/query-dataset.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"query-dataset.d.ts","sourceRoot":"","sources":["../../src/tools/query-dataset.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAgB,MAAM,qBAAqB,CAAC;AACvE,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAuB,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAG3G,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,eAAe,EACzB,SAAS,EAAE,aAAa,EACxB,IAAI,EAAE,OAAO,EACb,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,eAAe,CAAC,CA8D1B"}
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Query Dataset Tool
|
|
3
3
|
*
|
|
4
|
-
* Executes an ad-hoc dataset query with custom dimensions and
|
|
4
|
+
* Executes an ad-hoc dataset query with custom dimensions and measures.
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
7
|
-
export async function queryDatasetTool(datasets,
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
const { dataset: datasetName, dimensions, metrics, filters, grain, orderBy, limit } = validatedArgs;
|
|
6
|
+
import { parseToolArgs, queryDatasetArgsSchema, toMetricFilters } from './args.js';
|
|
7
|
+
export async function queryDatasetTool(datasets, analytics, args, options = {}) {
|
|
8
|
+
const validatedArgs = parseToolArgs(queryDatasetArgsSchema, 'query_dataset', args);
|
|
9
|
+
const { dataset: datasetName, dimensions, measures, filters, grain, orderBy, limit, offset } = validatedArgs;
|
|
11
10
|
if (!datasetName) {
|
|
12
11
|
throw new Error('dataset parameter is required');
|
|
13
12
|
}
|
|
@@ -15,30 +14,28 @@ export async function queryDatasetTool(datasets, executor, args) {
|
|
|
15
14
|
if (!dataset) {
|
|
16
15
|
throw new Error(`Dataset not found: ${datasetName}`);
|
|
17
16
|
}
|
|
18
|
-
if (!dimensions?.length && !
|
|
19
|
-
throw new Error('At least one dimension or
|
|
17
|
+
if (!dimensions?.length && !measures?.length) {
|
|
18
|
+
throw new Error('At least one dimension or measure must be specified');
|
|
20
19
|
}
|
|
21
20
|
// Build the query with proper types
|
|
22
21
|
const query = {
|
|
23
22
|
dimensions: dimensions || [],
|
|
24
|
-
measures:
|
|
25
|
-
filters: filters
|
|
23
|
+
measures: measures || [],
|
|
24
|
+
filters: toMetricFilters(filters),
|
|
26
25
|
orderBy: orderBy || [],
|
|
27
26
|
};
|
|
28
27
|
if (grain) {
|
|
29
28
|
query.by = grain;
|
|
30
29
|
}
|
|
31
|
-
// Apply limit with maximum cap
|
|
32
|
-
const MAX_LIMIT = 10000;
|
|
33
30
|
if (limit !== undefined) {
|
|
34
|
-
query.limit =
|
|
31
|
+
query.limit = limit;
|
|
35
32
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
},
|
|
33
|
+
if (offset !== undefined) {
|
|
34
|
+
query.offset = offset;
|
|
35
|
+
}
|
|
36
|
+
const result = await analytics.execute(dataset, query, {
|
|
37
|
+
runtime: {
|
|
38
|
+
tenant: options.tenantId ? { id: options.tenantId } : undefined,
|
|
42
39
|
},
|
|
43
40
|
});
|
|
44
41
|
// Format the response with proper types
|
|
@@ -48,6 +45,7 @@ export async function queryDatasetTool(datasets, executor, args) {
|
|
|
48
45
|
sql: result.meta?.sql,
|
|
49
46
|
timingMs: result.meta?.timingMs,
|
|
50
47
|
rowCount: result.data.length,
|
|
48
|
+
...(result.meta?.pagination ? { pagination: result.meta.pagination } : {}),
|
|
51
49
|
},
|
|
52
50
|
};
|
|
53
51
|
return {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Executes a metric query with optional dimensions, filters, grain, and sorting.
|
|
5
5
|
*/
|
|
6
|
-
import type {
|
|
7
|
-
import type { DatasetRegistry, MCPToolResponse } from '../types.js';
|
|
8
|
-
export declare function queryMetricTool(datasets: DatasetRegistry,
|
|
6
|
+
import type { DatasetClient } from '@hypequery/datasets';
|
|
7
|
+
import type { DatasetRegistry, MCPToolResponse, QueryToolOptions } from '../types.js';
|
|
8
|
+
export declare function queryMetricTool(datasets: DatasetRegistry, analytics: DatasetClient, args: unknown, options?: QueryToolOptions): Promise<MCPToolResponse>;
|
|
9
9
|
//# sourceMappingURL=query-metric.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query-metric.d.ts","sourceRoot":"","sources":["../../src/tools/query-metric.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"query-metric.d.ts","sourceRoot":"","sources":["../../src/tools/query-metric.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAe,MAAM,qBAAqB,CAAC;AACtE,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAuB,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAG3G,wBAAsB,eAAe,CACnC,QAAQ,EAAE,eAAe,EACzB,SAAS,EAAE,aAAa,EACxB,IAAI,EAAE,OAAO,EACb,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,eAAe,CAAC,CAqE1B"}
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Executes a metric query with optional dimensions, filters, grain, and sorting.
|
|
5
5
|
*/
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const validatedArgs = args;
|
|
9
|
-
const { dataset: datasetName, metric: metricName, dimensions, filters, grain, orderBy, limit } = validatedArgs;
|
|
6
|
+
import { parseToolArgs, queryMetricArgsSchema, toMetricFilters } from './args.js';
|
|
7
|
+
export async function queryMetricTool(datasets, analytics, args, options = {}) {
|
|
8
|
+
const validatedArgs = parseToolArgs(queryMetricArgsSchema, 'query_metric', args);
|
|
9
|
+
const { dataset: datasetName, metric: metricName, dimensions, filters, grain, orderBy, limit, offset } = validatedArgs;
|
|
10
10
|
if (!datasetName) {
|
|
11
11
|
throw new Error('dataset parameter is required');
|
|
12
12
|
}
|
|
@@ -25,22 +25,22 @@ export async function queryMetricTool(datasets, executor, args) {
|
|
|
25
25
|
// Build the query with proper types
|
|
26
26
|
const query = {
|
|
27
27
|
dimensions: dimensions || [],
|
|
28
|
-
filters: filters
|
|
28
|
+
filters: toMetricFilters(filters),
|
|
29
29
|
orderBy: orderBy || [],
|
|
30
30
|
};
|
|
31
31
|
if (grain) {
|
|
32
32
|
query.by = grain;
|
|
33
33
|
}
|
|
34
|
-
// Apply limit with maximum cap
|
|
35
|
-
const MAX_LIMIT = 10000;
|
|
36
34
|
if (limit !== undefined) {
|
|
37
|
-
query.limit =
|
|
35
|
+
query.limit = limit;
|
|
36
|
+
}
|
|
37
|
+
if (offset !== undefined) {
|
|
38
|
+
query.offset = offset;
|
|
38
39
|
}
|
|
39
40
|
// Execute the query
|
|
40
|
-
const result = await
|
|
41
|
+
const result = await analytics.execute(metric, query, {
|
|
41
42
|
runtime: {
|
|
42
|
-
|
|
43
|
-
tenant: undefined,
|
|
43
|
+
tenant: options.tenantId ? { id: options.tenantId } : undefined,
|
|
44
44
|
},
|
|
45
45
|
});
|
|
46
46
|
// Format the response with proper types
|
|
@@ -50,6 +50,7 @@ export async function queryMetricTool(datasets, executor, args) {
|
|
|
50
50
|
sql: result.meta?.sql,
|
|
51
51
|
timingMs: result.meta?.timingMs,
|
|
52
52
|
rowCount: result.data.length,
|
|
53
|
+
...(result.meta?.pagination ? { pagination: result.meta.pagination } : {}),
|
|
53
54
|
},
|
|
54
55
|
};
|
|
55
56
|
return {
|
package/dist/types.d.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Type definitions for MCP Server
|
|
3
3
|
*/
|
|
4
|
-
import type { MetricFilter, TimeGrain, MetricOrderBy } from '@hypequery/datasets';
|
|
4
|
+
import type { AnyDatasetInstance, MetricFilter, TimeGrain, MetricOrderBy } from '@hypequery/datasets';
|
|
5
5
|
/**
|
|
6
6
|
* Registry of datasets - maps dataset names to dataset instances
|
|
7
|
-
* Using flexible type to accommodate actual dataset structure
|
|
8
7
|
*/
|
|
9
|
-
export type DatasetRegistry = Record<string, Record<string, unknown>>;
|
|
8
|
+
export type DatasetRegistry = Record<string, AnyDatasetInstance | Record<string, unknown>>;
|
|
10
9
|
/**
|
|
11
10
|
* Arguments for query_metric tool
|
|
12
11
|
*/
|
|
@@ -18,6 +17,7 @@ export interface QueryMetricArgs {
|
|
|
18
17
|
grain?: TimeGrain;
|
|
19
18
|
orderBy?: MetricOrderBy[];
|
|
20
19
|
limit?: number;
|
|
20
|
+
offset?: number;
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
23
|
* Arguments for query_dataset tool
|
|
@@ -25,11 +25,15 @@ export interface QueryMetricArgs {
|
|
|
25
25
|
export interface QueryDatasetArgs {
|
|
26
26
|
dataset: string;
|
|
27
27
|
dimensions?: string[];
|
|
28
|
-
|
|
28
|
+
measures?: string[];
|
|
29
29
|
filters?: MetricFilter[];
|
|
30
30
|
grain?: TimeGrain;
|
|
31
31
|
orderBy?: MetricOrderBy[];
|
|
32
32
|
limit?: number;
|
|
33
|
+
offset?: number;
|
|
34
|
+
}
|
|
35
|
+
export interface QueryToolOptions {
|
|
36
|
+
tenantId?: string;
|
|
33
37
|
}
|
|
34
38
|
/**
|
|
35
39
|
* Arguments for get_dataset_schema tool
|
|
@@ -59,18 +63,48 @@ export interface DatasetSchema {
|
|
|
59
63
|
timeKey: string | null;
|
|
60
64
|
tenantKey: string | null;
|
|
61
65
|
dimensions: Record<string, DimensionSchema>;
|
|
66
|
+
measures: Record<string, MeasureSchema>;
|
|
62
67
|
metrics: Record<string, MetricSchema>;
|
|
68
|
+
filters: Record<string, FilterSchema>;
|
|
63
69
|
relationships: Record<string, RelationshipSchema>;
|
|
70
|
+
limits?: {
|
|
71
|
+
maxDimensions?: number;
|
|
72
|
+
maxMeasures?: number;
|
|
73
|
+
maxFilters?: number;
|
|
74
|
+
maxResultSize?: number;
|
|
75
|
+
};
|
|
64
76
|
}
|
|
65
77
|
/**
|
|
66
78
|
* Dimension schema in response
|
|
67
79
|
*/
|
|
68
80
|
export interface DimensionSchema {
|
|
69
81
|
type: string;
|
|
70
|
-
column: string;
|
|
82
|
+
column: string | null;
|
|
83
|
+
sql: string | null;
|
|
71
84
|
label: string;
|
|
72
85
|
description: string;
|
|
73
86
|
examples: string[];
|
|
87
|
+
filterable: boolean;
|
|
88
|
+
groupable: boolean;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Measure schema in response
|
|
92
|
+
*/
|
|
93
|
+
export interface MeasureSchema {
|
|
94
|
+
aggregation: string;
|
|
95
|
+
field: string;
|
|
96
|
+
sql: string | null;
|
|
97
|
+
label: string;
|
|
98
|
+
description: string;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Filter schema in response
|
|
102
|
+
*/
|
|
103
|
+
export interface FilterSchema {
|
|
104
|
+
field: string;
|
|
105
|
+
label: string;
|
|
106
|
+
description: string;
|
|
107
|
+
operators: string[] | null;
|
|
74
108
|
}
|
|
75
109
|
/**
|
|
76
110
|
* Metric schema in response
|
|
@@ -88,6 +122,9 @@ export interface MetricSchema {
|
|
|
88
122
|
export interface RelationshipSchema {
|
|
89
123
|
type: string;
|
|
90
124
|
target: string;
|
|
125
|
+
from?: string;
|
|
126
|
+
to?: string;
|
|
127
|
+
execution?: string;
|
|
91
128
|
description: string;
|
|
92
129
|
}
|
|
93
130
|
/**
|
|
@@ -97,6 +134,7 @@ export interface DatasetListItem {
|
|
|
97
134
|
name: string;
|
|
98
135
|
description: string;
|
|
99
136
|
dimensionCount: number;
|
|
137
|
+
measureCount?: number;
|
|
100
138
|
metricCount: number;
|
|
101
139
|
}
|
|
102
140
|
/**
|
|
@@ -113,6 +151,15 @@ export interface QueryResultMeta {
|
|
|
113
151
|
sql?: string;
|
|
114
152
|
timingMs?: number;
|
|
115
153
|
rowCount: number;
|
|
154
|
+
/**
|
|
155
|
+
* Offset pagination state. Present when the query specified a `limit`.
|
|
156
|
+
* `hasMore` lets callers know whether to request the next `offset` page.
|
|
157
|
+
*/
|
|
158
|
+
pagination?: {
|
|
159
|
+
limit: number;
|
|
160
|
+
offset: number;
|
|
161
|
+
hasMore: boolean;
|
|
162
|
+
};
|
|
116
163
|
}
|
|
117
164
|
/**
|
|
118
165
|
* Query result response
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,YAAY,EACZ,SAAS,EACT,aAAa,EACd,MAAM,qBAAqB,CAAC;AAE7B
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hypequery/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Model Context Protocol (MCP) server for Hypequery semantic layer",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
"dist"
|
|
21
21
|
],
|
|
22
22
|
"dependencies": {
|
|
23
|
+
"@hypequery/datasets": "^0.2.1",
|
|
23
24
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
24
|
-
"zod": "^3.23.8"
|
|
25
|
-
"@hypequery/datasets": "0.1.0"
|
|
25
|
+
"zod": "^3.23.8"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@types/node": "^20.11.30",
|