@hypequery/mcp 0.5.5 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +83 -6
  2. package/dist/api.type-test.d.ts +2 -0
  3. package/dist/api.type-test.d.ts.map +1 -0
  4. package/dist/api.type-test.js +14 -0
  5. package/dist/bin.js +2 -1
  6. package/dist/errors.d.ts +29 -0
  7. package/dist/errors.d.ts.map +1 -0
  8. package/dist/errors.js +65 -0
  9. package/dist/executor.d.ts +50 -0
  10. package/dist/executor.d.ts.map +1 -0
  11. package/dist/executor.js +103 -0
  12. package/dist/index.d.ts +8 -3
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +7 -2
  15. package/dist/protocol-server.d.ts +26 -0
  16. package/dist/protocol-server.d.ts.map +1 -0
  17. package/dist/protocol-server.js +48 -0
  18. package/dist/server.d.ts +15 -44
  19. package/dist/server.d.ts.map +1 -1
  20. package/dist/server.js +21 -271
  21. package/dist/stdio.d.ts +8 -0
  22. package/dist/stdio.d.ts.map +1 -0
  23. package/dist/stdio.js +14 -0
  24. package/dist/tools/args.d.ts +16 -16
  25. package/dist/tools/args.d.ts.map +1 -1
  26. package/dist/tools/args.js +9 -8
  27. package/dist/tools/introspect.d.ts +8 -6
  28. package/dist/tools/introspect.d.ts.map +1 -1
  29. package/dist/tools/introspect.js +45 -168
  30. package/dist/tools/list-datasets.d.ts.map +1 -1
  31. package/dist/tools/list-datasets.js +2 -8
  32. package/dist/tools/query-dataset.d.ts.map +1 -1
  33. package/dist/tools/query-dataset.js +26 -30
  34. package/dist/tools/query-metric.d.ts.map +1 -1
  35. package/dist/tools/query-metric.js +27 -31
  36. package/dist/tools/tool-manifest.d.ts +28 -0
  37. package/dist/tools/tool-manifest.d.ts.map +1 -0
  38. package/dist/tools/tool-manifest.js +302 -0
  39. package/dist/tools/utils/canonical-query-schemas.d.ts +9 -0
  40. package/dist/tools/utils/canonical-query-schemas.d.ts.map +1 -0
  41. package/dist/tools/utils/canonical-query-schemas.js +108 -0
  42. package/dist/tools/utils/execution-budget.d.ts +11 -0
  43. package/dist/tools/utils/execution-budget.d.ts.map +1 -0
  44. package/dist/tools/utils/execution-budget.js +71 -0
  45. package/dist/tools/utils/legacy-agent-catalog.d.ts +19 -0
  46. package/dist/tools/utils/legacy-agent-catalog.d.ts.map +1 -0
  47. package/dist/tools/utils/legacy-agent-catalog.js +171 -0
  48. package/dist/tools/utils/query-limits.d.ts +25 -0
  49. package/dist/tools/utils/query-limits.d.ts.map +1 -0
  50. package/dist/tools/utils/query-limits.js +69 -0
  51. package/dist/tools/utils/query-result.d.ts +4 -0
  52. package/dist/tools/utils/query-result.d.ts.map +1 -0
  53. package/dist/tools/utils/query-result.js +19 -0
  54. package/dist/tools/utils/query-schema.d.ts +8 -0
  55. package/dist/tools/utils/query-schema.d.ts.map +1 -0
  56. package/dist/tools/utils/query-schema.js +36 -0
  57. package/dist/tools/utils/tool-response.d.ts +6 -0
  58. package/dist/tools/utils/tool-response.d.ts.map +1 -0
  59. package/dist/tools/utils/tool-response.js +33 -0
  60. package/dist/types.d.ts +54 -58
  61. package/dist/types.d.ts.map +1 -1
  62. package/dist/types.js +9 -0
  63. package/dist/utils/tenant-config.d.ts +3 -0
  64. package/dist/utils/tenant-config.d.ts.map +1 -0
  65. package/dist/utils/tenant-config.js +23 -0
  66. package/dist/version.d.ts +2 -0
  67. package/dist/version.d.ts.map +1 -0
  68. package/dist/version.js +5 -0
  69. package/package.json +7 -3
package/dist/server.js CHANGED
@@ -1,286 +1,36 @@
1
1
  /**
2
- * MCP Server for Hypequery Semantic Layer
2
+ * Backwards-compatible Hypequery MCP server facade.
3
3
  *
4
- * Exposes datasets and metrics via Model Context Protocol (MCP)
5
- * for use with Claude Desktop, Cursor, and other MCP-compatible tools.
4
+ * New integrations can compose HypequeryMCPExecutor with
5
+ * HypequeryMCPProtocolServer and supply their own transport. Existing callers
6
+ * can continue to construct this class and call start() for stdio.
6
7
  */
7
- import { Server } from '@modelcontextprotocol/sdk/server/index.js';
8
- import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
9
- import { CallToolRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
10
- import { listDatasetsTool } from './tools/list-datasets.js';
11
- import { getDatasetSchemaTool } from './tools/introspect.js';
12
- import { queryMetricTool } from './tools/query-metric.js';
13
- import { queryDatasetTool } from './tools/query-dataset.js';
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
- }
38
- export class HypequeryMCPServer {
39
- server;
40
- config;
8
+ import { HypequeryMCPExecutor } from './executor.js';
9
+ import { HypequeryMCPProtocolServer } from './protocol-server.js';
10
+ export class HypequeryMCPServer extends HypequeryMCPProtocolServer {
41
11
  constructor(config) {
42
- validateTenantConfig(config);
43
- this.config = config;
44
- this.server = new Server({
45
- name: config.name ?? 'hypequery-mcp-server',
46
- version: config.version ?? '0.1.0',
47
- }, {
48
- capabilities: {
49
- tools: {},
50
- prompts: {},
51
- },
52
- });
53
- this.setupHandlers();
54
- }
55
- setupHandlers() {
56
- // List available tools
57
- this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
58
- tools: [
59
- {
60
- name: 'list_datasets',
61
- description: 'List all available datasets in the semantic layer',
62
- inputSchema: {
63
- type: 'object',
64
- properties: {},
65
- },
66
- },
67
- {
68
- name: 'get_dataset_schema',
69
- description: 'Get the schema (dimensions, measures, named metrics, filters, relationships) for a specific dataset',
70
- inputSchema: {
71
- type: 'object',
72
- properties: {
73
- dataset: {
74
- type: 'string',
75
- description: 'Name of the dataset to introspect',
76
- },
77
- },
78
- required: ['dataset'],
79
- },
80
- },
81
- {
82
- name: 'query_metric',
83
- description: 'Execute a metric query with optional dimensions, filters, time grain, and sorting',
84
- inputSchema: {
85
- type: 'object',
86
- properties: {
87
- dataset: {
88
- type: 'string',
89
- description: 'Name of the dataset containing the metric',
90
- },
91
- metric: {
92
- type: 'string',
93
- description: 'Name of the metric to query',
94
- },
95
- dimensions: {
96
- type: 'array',
97
- items: { type: 'string' },
98
- description: 'Dimensions to group by (optional)',
99
- },
100
- filters: {
101
- type: 'array',
102
- items: {
103
- type: 'object',
104
- properties: {
105
- field: { type: 'string' },
106
- operator: {
107
- type: 'string',
108
- enum: ['eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'in', 'notIn', 'between', 'like']
109
- },
110
- value: {},
111
- },
112
- required: ['field', 'operator', 'value'],
113
- },
114
- description: 'Filters to apply (optional)',
115
- },
116
- grain: {
117
- type: 'string',
118
- enum: ['day', 'week', 'month', 'quarter', 'year'],
119
- description: 'Time grain for time-series queries (optional)',
120
- },
121
- orderBy: {
122
- type: 'array',
123
- items: {
124
- type: 'object',
125
- properties: {
126
- field: { type: 'string' },
127
- direction: { type: 'string', enum: ['asc', 'desc'] },
128
- },
129
- required: ['field', 'direction'],
130
- },
131
- description: 'Sort order (optional)',
132
- },
133
- limit: {
134
- type: 'number',
135
- description: 'Maximum number of rows to return (optional)',
136
- },
137
- offset: {
138
- type: 'number',
139
- description: 'Number of rows to skip before returning results (optional)',
140
- },
141
- },
142
- required: ['dataset', 'metric'],
143
- },
144
- },
145
- {
146
- name: 'query_dataset',
147
- description: 'Execute an ad-hoc dataset query with custom dimensions and measures',
148
- inputSchema: {
149
- type: 'object',
150
- properties: {
151
- dataset: {
152
- type: 'string',
153
- description: 'Name of the dataset to query',
154
- },
155
- dimensions: {
156
- type: 'array',
157
- items: { type: 'string' },
158
- description: 'Dimensions to select',
159
- },
160
- measures: {
161
- type: 'array',
162
- items: { type: 'string' },
163
- description: 'Measures to calculate',
164
- },
165
- filters: {
166
- type: 'array',
167
- items: {
168
- type: 'object',
169
- properties: {
170
- field: { type: 'string' },
171
- operator: {
172
- type: 'string',
173
- enum: ['eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'in', 'notIn', 'between', 'like']
174
- },
175
- value: {},
176
- },
177
- required: ['field', 'operator', 'value'],
178
- },
179
- description: 'Filters to apply (optional)',
180
- },
181
- grain: {
182
- type: 'string',
183
- enum: ['day', 'week', 'month', 'quarter', 'year'],
184
- description: 'Time grain for time-series queries (optional)',
185
- },
186
- orderBy: {
187
- type: 'array',
188
- items: {
189
- type: 'object',
190
- properties: {
191
- field: { type: 'string' },
192
- direction: { type: 'string', enum: ['asc', 'desc'] },
193
- },
194
- required: ['field', 'direction'],
195
- },
196
- description: 'Sort order (optional)',
197
- },
198
- limit: {
199
- type: 'number',
200
- description: 'Maximum number of rows to return (optional)',
201
- },
202
- offset: {
203
- type: 'number',
204
- description: 'Number of rows to skip before returning results (optional)',
205
- },
206
- },
207
- required: ['dataset'],
208
- },
209
- },
210
- ],
211
- }));
212
- // Handle tool calls
213
- this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
214
- const { name, arguments: args } = request.params;
215
- try {
216
- switch (name) {
217
- case 'list_datasets':
218
- return await listDatasetsTool(this.config.datasets);
219
- case 'get_dataset_schema':
220
- return await getDatasetSchemaTool(this.config.datasets, args, { includeSql: this.config.includeSql });
221
- case 'query_metric':
222
- return await queryMetricTool(this.config.datasets, this.config.analytics, args, { tenantId: this.config.tenantId, includeSql: this.config.includeSql });
223
- case 'query_dataset':
224
- return await queryDatasetTool(this.config.datasets, this.config.analytics, args, { tenantId: this.config.tenantId, includeSql: this.config.includeSql });
225
- default:
226
- throw new Error(`Unknown tool: ${name}`);
227
- }
228
- }
229
- catch (error) {
230
- return {
231
- content: [
232
- {
233
- type: 'text',
234
- text: `Error: ${error instanceof Error ? error.message : String(error)}`,
235
- },
236
- ],
237
- isError: true,
238
- };
239
- }
240
- });
241
- // List available prompts
242
- this.server.setRequestHandler(ListPromptsRequestSchema, async () => ({
243
- prompts: [
244
- {
245
- name: 'dataset_guide',
246
- description: 'Guide for querying datasets with natural language',
247
- arguments: [
248
- {
249
- name: 'dataset',
250
- description: 'Name of the dataset to get guidance for',
251
- required: false,
252
- },
253
- ],
254
- },
255
- ],
256
- }));
257
- // Get prompt content
258
- this.server.setRequestHandler(GetPromptRequestSchema, async (request) => {
259
- const { name, arguments: args } = request.params;
260
- if (name === 'dataset_guide') {
261
- return datasetGuidePrompt(this.config.datasets, args?.dataset);
262
- }
263
- throw new Error(`Unknown prompt: ${name}`);
12
+ const executor = new HypequeryMCPExecutor(config);
13
+ super({
14
+ executor,
15
+ name: config.name,
16
+ version: config.version,
264
17
  });
265
18
  }
266
19
  /**
267
- * Start the MCP server with stdio transport
20
+ * Start with the legacy stdio transport.
21
+ *
22
+ * @deprecated Prefer connect(transport) or startStdioMCPServer(config).
268
23
  */
269
24
  async start() {
270
- const transport = new StdioServerTransport();
271
- await this.server.connect(transport);
272
- // Log to stderr (stdout is used for MCP protocol)
273
- console.error('Hypequery MCP Server started');
274
- }
275
- /**
276
- * Stop the MCP server
277
- */
278
- async stop() {
279
- await this.server.close();
25
+ const { connectMCPServerStdio } = await import('./stdio.js');
26
+ await connectMCPServerStdio(this);
280
27
  }
281
28
  }
282
29
  /**
283
- * Create and start an MCP server
30
+ * Create and start a backwards-compatible stdio MCP server.
31
+ *
32
+ * @deprecated Prefer createMCPExecutor with createMCPProtocolServer, or
33
+ * startStdioMCPServer for an explicit stdio lifecycle.
284
34
  */
285
35
  export async function createMCPServer(config) {
286
36
  const server = new HypequeryMCPServer(config);
@@ -0,0 +1,8 @@
1
+ import type { MCPServerConfig } from './executor.js';
2
+ import type { HypequeryMCPProtocolServer } from './protocol-server.js';
3
+ import { HypequeryMCPServer } from './server.js';
4
+ /** Connect an existing Hypequery MCP server to the stdio transport. */
5
+ export declare function connectMCPServerStdio(server: HypequeryMCPProtocolServer): Promise<void>;
6
+ /** Create and start the backwards-compatible stdio MCP server. */
7
+ export declare function startStdioMCPServer(config: MCPServerConfig): Promise<HypequeryMCPServer>;
8
+ //# sourceMappingURL=stdio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../src/stdio.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD,uEAAuE;AACvE,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,0BAA0B,GACjC,OAAO,CAAC,IAAI,CAAC,CAKf;AAED,kEAAkE;AAClE,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,eAAe,GACtB,OAAO,CAAC,kBAAkB,CAAC,CAI7B"}
package/dist/stdio.js ADDED
@@ -0,0 +1,14 @@
1
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
2
+ import { HypequeryMCPServer } from './server.js';
3
+ /** Connect an existing Hypequery MCP server to the stdio transport. */
4
+ export async function connectMCPServerStdio(server) {
5
+ await server.connect(new StdioServerTransport());
6
+ // MCP stdio owns stdout, so lifecycle logging must use stderr.
7
+ console.error('Hypequery MCP Server started');
8
+ }
9
+ /** Create and start the backwards-compatible stdio MCP server. */
10
+ export async function startStdioMCPServer(config) {
11
+ const server = new HypequeryMCPServer(config);
12
+ await connectMCPServerStdio(server);
13
+ return server;
14
+ }
@@ -7,12 +7,12 @@ export declare const queryMetricArgsSchema: z.ZodObject<{
7
7
  operator: z.ZodEnum<["eq", "neq", "gt", "gte", "lt", "lte", "in", "notIn", "between", "like"]>;
8
8
  value: z.ZodEffects<z.ZodAny, any, any>;
9
9
  }, "strict", z.ZodTypeAny, {
10
- operator: "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "notIn" | "between" | "like";
11
10
  field: string;
11
+ operator: "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "notIn" | "between" | "like";
12
12
  value?: any;
13
13
  }, {
14
- operator: "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "notIn" | "between" | "like";
15
14
  field: string;
15
+ operator: "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "notIn" | "between" | "like";
16
16
  value?: any;
17
17
  }>, "many">>;
18
18
  grain: z.ZodOptional<z.ZodEnum<["day", "week", "month", "quarter", "year"]>>;
@@ -32,14 +32,14 @@ export declare const queryMetricArgsSchema: z.ZodObject<{
32
32
  dataset: z.ZodOptional<z.ZodString>;
33
33
  metric: z.ZodOptional<z.ZodString>;
34
34
  }, "strict", z.ZodTypeAny, {
35
- dataset?: string | undefined;
36
- metric?: string | undefined;
37
35
  dimensions?: string[] | undefined;
38
36
  filters?: {
39
- operator: "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "notIn" | "between" | "like";
40
37
  field: string;
38
+ operator: "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "notIn" | "between" | "like";
41
39
  value?: any;
42
40
  }[] | undefined;
41
+ metric?: string | undefined;
42
+ dataset?: string | undefined;
43
43
  grain?: "day" | "week" | "month" | "quarter" | "year" | undefined;
44
44
  orderBy?: {
45
45
  field: string;
@@ -48,14 +48,14 @@ export declare const queryMetricArgsSchema: z.ZodObject<{
48
48
  limit?: number | undefined;
49
49
  offset?: number | undefined;
50
50
  }, {
51
- dataset?: string | undefined;
52
- metric?: string | undefined;
53
51
  dimensions?: string[] | undefined;
54
52
  filters?: {
55
- operator: "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "notIn" | "between" | "like";
56
53
  field: string;
54
+ operator: "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "notIn" | "between" | "like";
57
55
  value?: any;
58
56
  }[] | undefined;
57
+ metric?: string | undefined;
58
+ dataset?: string | undefined;
59
59
  grain?: "day" | "week" | "month" | "quarter" | "year" | undefined;
60
60
  orderBy?: {
61
61
  field: string;
@@ -71,12 +71,12 @@ export declare const queryDatasetArgsSchema: z.ZodObject<{
71
71
  operator: z.ZodEnum<["eq", "neq", "gt", "gte", "lt", "lte", "in", "notIn", "between", "like"]>;
72
72
  value: z.ZodEffects<z.ZodAny, any, any>;
73
73
  }, "strict", z.ZodTypeAny, {
74
- operator: "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "notIn" | "between" | "like";
75
74
  field: string;
75
+ operator: "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "notIn" | "between" | "like";
76
76
  value?: any;
77
77
  }, {
78
- operator: "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "notIn" | "between" | "like";
79
78
  field: string;
79
+ operator: "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "notIn" | "between" | "like";
80
80
  value?: any;
81
81
  }>, "many">>;
82
82
  grain: z.ZodOptional<z.ZodEnum<["day", "week", "month", "quarter", "year"]>>;
@@ -96,13 +96,14 @@ export declare const queryDatasetArgsSchema: z.ZodObject<{
96
96
  dataset: z.ZodOptional<z.ZodString>;
97
97
  measures: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
98
98
  }, "strict", z.ZodTypeAny, {
99
- dataset?: string | undefined;
100
99
  dimensions?: string[] | undefined;
101
100
  filters?: {
102
- operator: "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "notIn" | "between" | "like";
103
101
  field: string;
102
+ operator: "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "notIn" | "between" | "like";
104
103
  value?: any;
105
104
  }[] | undefined;
105
+ measures?: string[] | undefined;
106
+ dataset?: string | undefined;
106
107
  grain?: "day" | "week" | "month" | "quarter" | "year" | undefined;
107
108
  orderBy?: {
108
109
  field: string;
@@ -110,15 +111,15 @@ export declare const queryDatasetArgsSchema: z.ZodObject<{
110
111
  }[] | undefined;
111
112
  limit?: number | undefined;
112
113
  offset?: number | undefined;
113
- measures?: string[] | undefined;
114
114
  }, {
115
- dataset?: string | undefined;
116
115
  dimensions?: string[] | undefined;
117
116
  filters?: {
118
- operator: "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "notIn" | "between" | "like";
119
117
  field: string;
118
+ operator: "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "notIn" | "between" | "like";
120
119
  value?: any;
121
120
  }[] | undefined;
121
+ measures?: string[] | undefined;
122
+ dataset?: string | undefined;
122
123
  grain?: "day" | "week" | "month" | "quarter" | "year" | undefined;
123
124
  orderBy?: {
124
125
  field: string;
@@ -126,7 +127,6 @@ export declare const queryDatasetArgsSchema: z.ZodObject<{
126
127
  }[] | undefined;
127
128
  limit?: number | undefined;
128
129
  offset?: number | undefined;
129
- measures?: string[] | undefined;
130
130
  }>;
131
131
  export declare function parseToolArgs<T>(schema: z.ZodType<T>, toolName: string, args: unknown): T;
132
132
  export declare function toMetricFilters(filters?: Array<{
@@ -1 +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"}
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;AA+BnF,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,CASzF;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"}
@@ -1,6 +1,7 @@
1
1
  import { z } from 'zod';
2
2
  import { SEMANTIC_FILTER_OPERATORS } from '@hypequery/datasets';
3
- import { MAX_QUERY_LIMIT } from '../types.js';
3
+ import { MCPToolError } from '../errors.js';
4
+ import { MAX_QUERY_DIMENSIONS, MAX_QUERY_FILTERS, MAX_QUERY_LIMIT, MAX_QUERY_MEASURES, MAX_QUERY_OFFSET, MAX_QUERY_ORDER_BY, } from '../types.js';
4
5
  const filterSchema = z.object({
5
6
  field: z.string().min(1),
6
7
  operator: z.enum(SEMANTIC_FILTER_OPERATORS),
@@ -11,12 +12,12 @@ const orderBySchema = z.object({
11
12
  direction: z.enum(['asc', 'desc']),
12
13
  }).strict();
13
14
  const baseQuerySchema = z.object({
14
- dimensions: z.array(z.string().min(1)).optional(),
15
- filters: z.array(filterSchema).optional(),
15
+ dimensions: z.array(z.string().min(1)).max(MAX_QUERY_DIMENSIONS).optional(),
16
+ filters: z.array(filterSchema).max(MAX_QUERY_FILTERS).optional(),
16
17
  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(),
18
+ orderBy: z.array(orderBySchema).max(MAX_QUERY_ORDER_BY).optional(),
19
+ limit: z.number().int().positive().max(MAX_QUERY_LIMIT).optional(),
20
+ offset: z.number().int().nonnegative().max(MAX_QUERY_OFFSET).optional(),
20
21
  }).strict();
21
22
  export const queryMetricArgsSchema = baseQuerySchema.extend({
22
23
  dataset: z.string().min(1).optional(),
@@ -24,7 +25,7 @@ export const queryMetricArgsSchema = baseQuerySchema.extend({
24
25
  });
25
26
  export const queryDatasetArgsSchema = baseQuerySchema.extend({
26
27
  dataset: z.string().min(1).optional(),
27
- measures: z.array(z.string().min(1)).optional(),
28
+ measures: z.array(z.string().min(1)).max(MAX_QUERY_MEASURES).optional(),
28
29
  });
29
30
  function formatZodError(error) {
30
31
  return error.issues
@@ -37,7 +38,7 @@ function formatZodError(error) {
37
38
  export function parseToolArgs(schema, toolName, args) {
38
39
  const result = schema.safeParse(args);
39
40
  if (!result.success) {
40
- throw new Error(`Invalid ${toolName} arguments: ${formatZodError(result.error)}`);
41
+ throw new MCPToolError('MCP_INVALID_ARGUMENTS', `Invalid ${toolName} arguments: ${formatZodError(result.error)}`);
41
42
  }
42
43
  return result.data;
43
44
  }
@@ -1,9 +1,11 @@
1
+ /** Agent-safe dataset discovery and separately authorized trusted debugging. */
2
+ import { type TrustedDebugCatalogAuthorization } from '@hypequery/datasets';
3
+ import type { DatasetRegistry, MCPToolResponse, SchemaToolOptions } from '../types.js';
4
+ export declare function getDatasetSchemaTool(datasets: DatasetRegistry, args: unknown, _options?: SchemaToolOptions): Promise<MCPToolResponse>;
1
5
  /**
2
- * Get Dataset Schema Tool
3
- *
4
- * Returns the complete schema for a dataset including dimensions, measures,
5
- * named metrics, filters, and relationships.
6
+ * Physical catalog diagnostics for a caller that has already passed a
7
+ * separate authorization check. This projection is intentionally not
8
+ * registered as an agent-facing MCP tool.
6
9
  */
7
- import type { DatasetRegistry, MCPToolResponse, SchemaToolOptions } from '../types.js';
8
- export declare function getDatasetSchemaTool(datasets: DatasetRegistry, args: unknown, options?: SchemaToolOptions): Promise<MCPToolResponse>;
10
+ export declare function getTrustedDatasetSchema(datasets: DatasetRegistry, args: unknown, authorization: TrustedDebugCatalogAuthorization): Promise<unknown>;
9
11
  //# sourceMappingURL=introspect.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"introspect.d.ts","sourceRoot":"","sources":["../../src/tools/introspect.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EACV,eAAe,EAEf,eAAe,EAOf,iBAAiB,EAClB,MAAM,aAAa,CAAC;AAMrB,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,eAAe,EACzB,IAAI,EAAE,OAAO,EACb,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,eAAe,CAAC,CAuL1B"}
1
+ {"version":3,"file":"introspect.d.ts","sourceRoot":"","sources":["../../src/tools/introspect.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAEhF,OAAO,EAML,KAAK,gCAAgC,EACtC,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EACV,eAAe,EAEf,eAAe,EACf,iBAAiB,EAClB,MAAM,aAAa,CAAC;AAkBrB,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,eAAe,EACzB,IAAI,EAAE,OAAO,EACb,QAAQ,GAAE,iBAAsB,GAC/B,OAAO,CAAC,eAAe,CAAC,CAuB1B;AAED;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,eAAe,EACzB,IAAI,EAAE,OAAO,EACb,aAAa,EAAE,gCAAgC,GAC9C,OAAO,CAAC,OAAO,CAAC,CAclB"}