@hypequery/mcp 0.5.4 → 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 +103 -230
  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 +23 -5
package/README.md CHANGED
@@ -1,293 +1,166 @@
1
1
  # @hypequery/mcp
2
2
 
3
- Model Context Protocol (MCP) server for Hypequery semantic layer. Exposes datasets and metrics to AI agents like Claude Desktop, Cursor, and other MCP-compatible tools.
3
+ A governed ClickHouse MCP server for AI agents.
4
4
 
5
- ## Features
5
+ `@hypequery/mcp` turns your hypequery datasets and metrics into Model Context Protocol tools for Claude, Cursor, and other MCP clients. Agents can discover and query approved analytics without receiving unrestricted SQL access or database credentials.
6
6
 
7
- - **MCP Tools**: List datasets, introspect schemas, query metrics and datasets
8
- - **Natural Language**: AI-friendly prompts and responses
9
- - **Type-Safe**: Full TypeScript support with the Hypequery semantic layer
10
- - **ClickHouse Native**: Optimized for ClickHouse analytics workloads
11
-
12
- ## Installation
7
+ ## Install
13
8
 
14
9
  ```bash
15
- npm install @hypequery/mcp
16
- # or
17
- pnpm add @hypequery/mcp
10
+ npm install @hypequery/mcp @hypequery/datasets @hypequery/clickhouse
18
11
  ```
19
12
 
20
- ## Quick Start
21
-
22
- ### 1. Create an MCP Config File
13
+ ## Expose your semantic layer
23
14
 
24
- Create `mcp-config.ts`:
15
+ ```ts
16
+ // mcp-config.ts
17
+ import { publishDatasets } from '@hypequery/datasets';
25
18
 
26
- ```typescript
27
- import { createDatasetClient } from '@hypequery/datasets';
28
- import { createQueryBuilder } from '@hypequery/clickhouse';
29
- import { OrdersDataset, CustomersDataset } from './datasets/index.js';
30
-
31
- const revenue = OrdersDataset.metric('revenue', { measure: 'revenue' });
32
- const customerCount = CustomersDataset.metric('customerCount', {
33
- measure: 'customerCount',
34
- });
35
-
36
- // Export your datasets
37
- export const datasets = {
38
- orders: {
39
- ...OrdersDataset,
40
- metrics: { revenue },
41
- },
42
- customers: {
43
- ...CustomersDataset,
44
- metrics: { customerCount },
45
- },
46
- };
47
-
48
- // Export the semantic runner consumed by the MCP server
49
- const db = createQueryBuilder({
50
- url: process.env.CLICKHOUSE_URL,
51
- username: process.env.CLICKHOUSE_USER,
52
- password: process.env.CLICKHOUSE_PASSWORD,
53
- database: process.env.CLICKHOUSE_DATABASE,
54
- });
19
+ export const datasets = publishDatasets()
20
+ .publish(Orders, { metrics: { revenue } })
21
+ .build();
55
22
 
56
23
  export const analytics = createDatasetClient({ queryBuilder: db });
57
24
  ```
58
25
 
59
- ### 2. Run the MCP Server
26
+ Compile the config, then start the stdio server:
60
27
 
61
28
  ```bash
62
- npx hypequery-mcp --config ./mcp-config.js
29
+ npx hypequery-mcp --config /absolute/path/to/mcp-config.js
63
30
  ```
64
31
 
65
- ### 3. Configure Claude Desktop
66
-
67
- Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
32
+ Add it to an MCP client:
68
33
 
69
34
  ```json
70
35
  {
71
36
  "mcpServers": {
72
- "hypequery": {
37
+ "hypequery-clickhouse": {
73
38
  "command": "npx",
74
- "args": ["hypequery-mcp", "--config", "/absolute/path/to/mcp-config.js"]
39
+ "args": [
40
+ "hypequery-mcp",
41
+ "--config",
42
+ "/absolute/path/to/mcp-config.js"
43
+ ]
75
44
  }
76
45
  }
77
46
  }
78
47
  ```
79
48
 
80
- ### 4. Use with Claude
81
-
82
- Now you can ask Claude to query your data:
83
-
84
- > "Show me revenue by region for the last month"
85
-
86
- > "What are the top 10 customers by order count?"
87
-
88
- > "List all available datasets"
89
-
90
- ## Available Tools
91
-
92
- ### `list_datasets`
93
-
94
- Lists all available datasets with their descriptions.
95
-
96
- **Example:**
97
- ```typescript
98
- {
99
- "name": "list_datasets"
100
- }
101
- ```
102
-
103
- **Response:**
104
- ```json
105
- {
106
- "datasets": [
107
- {
108
- "name": "orders",
109
- "description": "Customer orders and revenue data",
110
- "dimensionCount": 5,
111
- "measureCount": 4,
112
- "metricCount": 4
113
- }
114
- ],
115
- "total": 1
116
- }
117
- ```
118
-
119
- ### `get_dataset_schema`
120
-
121
- Gets the complete schema for a dataset.
122
-
123
- **Example:**
124
- ```typescript
125
- {
126
- "name": "get_dataset_schema",
127
- "arguments": {
128
- "dataset": "orders"
129
- }
130
- }
131
- ```
49
+ Now an agent can ask, “Show revenue by region for the last month,” using the same metric definition as your backend and dashboard.
132
50
 
133
- **Response:**
134
- ```json
135
- {
136
- "name": "orders",
137
- "dimensions": {
138
- "region": { "type": "string", "label": "Region" },
139
- "status": { "type": "string", "label": "Order Status" }
140
- },
141
- "measures": {
142
- "revenue": { "aggregation": "sum", "field": "amount", "label": "Revenue" },
143
- "orderCount": { "aggregation": "count", "field": "id", "label": "Order Count" }
144
- },
145
- "metrics": {
146
- "totalRevenue": { "type": "metric", "aggregation": "revenue", "label": "Total Revenue" }
147
- }
148
- }
149
- ```
51
+ ## Tools agents receive
150
52
 
151
- ### `query_metric`
53
+ - `list_datasets` discovers available analytics models;
54
+ - `get_dataset_schema` explains dimensions, measures, metrics, and relationships;
55
+ - `query_metric` executes named KPIs;
56
+ - `query_dataset` explores the fields you chose to publish.
152
57
 
153
- Executes a pre-defined metric query.
58
+ Every tool declares an output schema and returns the same result twice: MCP
59
+ `structuredContent` for clients that support typed results, and compact JSON in
60
+ the text content block for compatibility. Query metadata includes row count,
61
+ timing when available, pagination state, and cache outcome. Tools also advertise
62
+ human-readable titles and read-only, non-destructive, idempotent annotations.
154
63
 
155
- **Example:**
156
- ```typescript
157
- {
158
- "name": "query_metric",
159
- "arguments": {
160
- "dataset": "orders",
161
- "metric": "revenue",
162
- "dimensions": ["region"],
163
- "filters": [
164
- { "field": "status", "operator": "eq", "value": "completed" }
165
- ],
166
- "grain": "month",
167
- "orderBy": [
168
- { "field": "revenue", "direction": "desc" }
169
- ],
170
- "limit": 10
171
- }
172
- }
173
- ```
64
+ Tool failures use a stable structured envelope:
174
65
 
175
- **Response:**
176
66
  ```json
177
67
  {
178
- "data": [
179
- { "region": "US", "month": "2024-01", "revenue": 125000 },
180
- { "region": "EU", "month": "2024-01", "revenue": 98000 }
181
- ],
182
- "meta": {
183
- "sql": "SELECT...",
184
- "timingMs": 45,
185
- "rowCount": 2
68
+ "error": {
69
+ "code": "MCP_INVALID_ARGUMENTS",
70
+ "category": "correctable_input",
71
+ "message": "Invalid query_dataset arguments: ...",
72
+ "retryable": false,
73
+ "correctable": true
186
74
  }
187
75
  }
188
76
  ```
189
77
 
190
- ### `query_dataset`
191
-
192
- Executes an ad-hoc dataset query with custom dimensions and measures.
193
-
194
- **Example:**
195
- ```typescript
196
- {
197
- "name": "query_dataset",
198
- "arguments": {
199
- "dataset": "orders",
200
- "dimensions": ["region", "status"],
201
- "measures": ["revenue", "orderCount"],
202
- "limit": 100
203
- }
204
- }
205
- ```
78
+ Unclassified backend failures are redacted to `MCP_EXECUTION_FAILED`; database
79
+ error details and physical SQL are not copied into agent-facing errors.
206
80
 
207
- ## Programmatic Usage
81
+ ## Safer than raw SQL access
208
82
 
209
- You can also use the MCP server programmatically in your application:
83
+ - Tool schemas come from your TypeScript semantic layer.
84
+ - Advertised schemas and runtime validation use the same canonical catalog
85
+ compiler and deterministic manifest hash.
86
+ - Filters, fields, ordering, and limits are validated.
87
+ - ClickHouse credentials remain in the server process.
88
+ - SQL text stays hidden by default.
89
+ - Tenant identity comes from trusted host configuration, never the prompt.
210
90
 
211
- ```typescript
212
- import { createMCPServer } from '@hypequery/mcp';
213
- import { createDatasetClient } from '@hypequery/datasets';
214
- import { datasets } from './datasets/index.js';
91
+ For tenant-scoped datasets, run the server programmatically with the trusted tenant ID:
215
92
 
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
- });
222
-
223
- const server = await createMCPServer({
93
+ ```ts
94
+ await createMCPServer({
224
95
  datasets,
225
96
  analytics,
226
- name: 'my-analytics-mcp',
97
+ name: 'acme-analytics',
227
98
  version: '1.0.0',
99
+ tenantId: session.accountId,
100
+ queryLimits: {
101
+ defaultResultSize: 100,
102
+ maxResultSize: 1_000,
103
+ maxOffset: 10_000,
104
+ },
105
+ executionBudget: {
106
+ timeoutMs: 30_000,
107
+ maxResponseBytes: 1_048_576,
108
+ },
228
109
  });
229
-
230
- // Server is now running via stdio transport
231
110
  ```
232
111
 
233
- ## Filter Operators
234
-
235
- - `eq`: Equal to
236
- - `neq`: Not equal to
237
- - `gt`: Greater than
238
- - `gte`: Greater than or equal to
239
- - `lt`: Less than
240
- - `lte`: Less than or equal to
241
- - `in`: In list
242
- - `notIn`: Not in list
243
- - `between`: Between two values
244
- - `like`: Pattern match (SQL LIKE)
245
-
246
- ## Time Grains
247
-
248
- - `day`: Daily aggregation
249
- - `week`: Weekly aggregation
250
- - `month`: Monthly aggregation
251
- - `quarter`: Quarterly aggregation
252
- - `year`: Yearly aggregation
112
+ Every query receives a server-side limit even when the agent omits one. The
113
+ effective ceiling is the lowest applicable server or Dataset limit. Dimensions,
114
+ measures, filters, ordering, and pagination offsets also have hard package
115
+ ceilings that server configuration may lower but cannot raise.
253
116
 
254
- ## Prompts
117
+ Query calls also have a hard wall-clock deadline and UTF-8 response-byte
118
+ ceiling. Client cancellation and local deadlines propagate through the semantic
119
+ client to the backing ClickHouse request. Budget failures use the stable
120
+ `MCP_REQUEST_CANCELLED`, `MCP_QUERY_TIMEOUT`, and `MCP_RESULT_TOO_LARGE`
121
+ classifications.
255
122
 
256
- The MCP server also exposes a `dataset_guide` prompt that provides natural language guidance for querying datasets.
123
+ ## Embed in another MCP transport
257
124
 
258
- ## Environment Variables
125
+ The semantic executor is independent of stdio and network lifecycle. A hosted
126
+ gateway can inject its own MCP transport without reimplementing Hypequery's
127
+ tools, prompts, catalog schemas, or validation:
259
128
 
260
- Your config file can use environment variables for database credentials:
129
+ ```ts
130
+ import {
131
+ createMCPExecutor,
132
+ createMCPProtocolServer,
133
+ } from '@hypequery/mcp';
261
134
 
262
- ```typescript
263
- const analytics = createDatasetClient({
264
- url: process.env.CLICKHOUSE_URL || 'http://localhost:8123',
265
- username: process.env.CLICKHOUSE_USER || 'default',
266
- password: process.env.CLICKHOUSE_PASSWORD,
267
- database: process.env.CLICKHOUSE_DATABASE || 'default',
135
+ const executor = createMCPExecutor({
136
+ datasets,
137
+ analytics,
138
+ tenantId: trustedPrincipal.tenantId,
268
139
  });
269
- ```
270
-
271
- ## Troubleshooting
272
140
 
273
- ### MCP server not connecting
274
-
275
- 1. Check that the config file path is absolute, not relative
276
- 2. Ensure the config file exports both `datasets` and `analytics`
277
- 3. Check Claude Desktop logs for errors
141
+ const server = createMCPProtocolServer({
142
+ executor,
143
+ name: 'acme-hosted-analytics',
144
+ version: '1.0.0',
145
+ });
278
146
 
279
- ### Queries failing
147
+ await server.connect(hostTransport);
148
+ ```
280
149
 
281
- 1. Verify your ClickHouse connection is working
282
- 2. Check that dataset definitions match your database schema
283
- 3. For trusted local debugging, start the programmatic server with `includeSql: true` and inspect `meta.sql` in responses
150
+ `hostTransport` can be an MCP SDK in-memory, stdio, or hosted transport. This
151
+ package does not create an HTTP endpoint; authentication, routing, and network
152
+ lifecycle remain responsibilities of the host. For an explicit local adapter,
153
+ use `startStdioMCPServer(config)`. The existing `createMCPServer(config)` and
154
+ `HypequeryMCPServer.start()` APIs remain available for compatibility.
284
155
 
285
- ## Related Packages
156
+ ## Learn more
286
157
 
287
- - `@hypequery/datasets` - Semantic layer DSL
288
- - `@hypequery/clickhouse` - ClickHouse query builder
289
- - `@hypequery/serve` - HTTP server for analytics endpoints
158
+ - [ClickHouse MCP overview](https://hypequery.com/clickhouse-mcp)
159
+ - [MCP configuration](https://hypequery.com/docs/mcp/configuration)
160
+ - [MCP tools](https://hypequery.com/docs/mcp/tools)
161
+ - [MCP safety](https://hypequery.com/docs/mcp/safety)
162
+ - [Current capabilities](https://hypequery.com/docs/capabilities)
290
163
 
291
164
  ## License
292
165
 
293
- Apache-2.0
166
+ Apache-2.0.
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=api.type-test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.type-test.d.ts","sourceRoot":"","sources":["../src/api.type-test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,14 @@
1
+ import { expectTypeOf, it } from 'vitest';
2
+ import { HypequeryMCPExecutor, HypequeryMCPProtocolServer, HypequeryMCPServer, MCPToolError, connectMCPServerStdio, createMCPExecutor, createMCPProtocolServer, createMCPServer, startStdioMCPServer, } from './index.js';
3
+ it('exports the transport-neutral and backwards-compatible MCP APIs', () => {
4
+ expectTypeOf(HypequeryMCPExecutor).toBeConstructibleWith({});
5
+ expectTypeOf(HypequeryMCPProtocolServer).toBeConstructibleWith({});
6
+ expectTypeOf(HypequeryMCPServer).toBeConstructibleWith({});
7
+ expectTypeOf(createMCPExecutor).returns.toMatchTypeOf();
8
+ expectTypeOf(createMCPProtocolServer).returns.toMatchTypeOf();
9
+ expectTypeOf(connectMCPServerStdio).returns.toMatchTypeOf();
10
+ expectTypeOf(startStdioMCPServer).returns.toMatchTypeOf();
11
+ expectTypeOf(createMCPServer).returns.toMatchTypeOf();
12
+ expectTypeOf(new MCPToolError('MCP_UNAUTHORIZED', 'Forbidden').code)
13
+ .toMatchTypeOf();
14
+ });
package/dist/bin.js CHANGED
@@ -12,6 +12,7 @@ import { createMCPServer } from './server.js';
12
12
  import { pathToFileURL } from 'url';
13
13
  import { resolve } from 'path';
14
14
  import { format } from 'util';
15
+ import { MCP_PACKAGE_VERSION } from './version.js';
15
16
  function routeConsoleOutputToStderr() {
16
17
  const write = (...args) => {
17
18
  process.stderr.write(`${format(...args)}\n`);
@@ -53,7 +54,7 @@ async function main() {
53
54
  datasets,
54
55
  analytics,
55
56
  name: 'hypequery-mcp-server',
56
- version: '0.1.0',
57
+ version: MCP_PACKAGE_VERSION,
57
58
  });
58
59
  // Keep the process running
59
60
  process.on('SIGINT', () => {
@@ -0,0 +1,29 @@
1
+ export type MCPToolErrorCode = 'MCP_INVALID_ARGUMENTS' | 'MCP_NOT_FOUND' | 'MCP_UNKNOWN_TOOL' | 'MCP_UNAUTHORIZED' | 'MCP_STALE_CONTRACT' | 'MCP_REQUEST_CANCELLED' | 'MCP_QUERY_TIMEOUT' | 'MCP_RESULT_TOO_LARGE' | 'MCP_EXECUTION_FAILED';
2
+ export type MCPToolErrorCategory = 'correctable_input' | 'unauthorized' | 'stale_contract' | 'budget' | 'internal';
3
+ /** @deprecated Use MCPToolErrorCode. */
4
+ export type MCPExecutionErrorCode = Extract<MCPToolErrorCode, 'MCP_REQUEST_CANCELLED' | 'MCP_QUERY_TIMEOUT' | 'MCP_RESULT_TOO_LARGE'>;
5
+ export interface MCPErrorDetails {
6
+ code: MCPToolErrorCode;
7
+ category: MCPToolErrorCategory;
8
+ message: string;
9
+ retryable: boolean;
10
+ correctable: boolean;
11
+ }
12
+ export declare class MCPToolError extends Error {
13
+ readonly code: MCPToolErrorCode;
14
+ readonly category: MCPToolErrorCategory;
15
+ readonly retryable: boolean;
16
+ readonly correctable: boolean;
17
+ constructor(code: MCPToolErrorCode, message: string, options?: {
18
+ category?: MCPToolErrorCategory;
19
+ retryable?: boolean;
20
+ correctable?: boolean;
21
+ });
22
+ }
23
+ export declare class MCPExecutionBudgetError extends MCPToolError {
24
+ readonly code: MCPExecutionErrorCode;
25
+ constructor(code: MCPExecutionErrorCode, message: string);
26
+ }
27
+ export declare function classifyMCPToolError(error: unknown): MCPErrorDetails;
28
+ export declare function formatMCPToolError(error: unknown): string;
29
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,gBAAgB,GACxB,uBAAuB,GACvB,eAAe,GACf,kBAAkB,GAClB,kBAAkB,GAClB,oBAAoB,GACpB,uBAAuB,GACvB,mBAAmB,GACnB,sBAAsB,GACtB,sBAAsB,CAAC;AAE3B,MAAM,MAAM,oBAAoB,GAC5B,mBAAmB,GACnB,cAAc,GACd,gBAAgB,GAChB,QAAQ,GACR,UAAU,CAAC;AAEf,wCAAwC;AACxC,MAAM,MAAM,qBAAqB,GAAG,OAAO,CACzC,gBAAgB,EAChB,uBAAuB,GAAG,mBAAmB,GAAG,sBAAsB,CACvE,CAAC;AAEF,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,gBAAgB,CAAC;IACvB,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;CACtB;AAsBD,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,CAAC;IACxC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;gBAG5B,IAAI,EAAE,gBAAgB,EACtB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;QACP,QAAQ,CAAC,EAAE,oBAAoB,CAAC;QAChC,SAAS,CAAC,EAAE,OAAO,CAAC;QACpB,WAAW,CAAC,EAAE,OAAO,CAAC;KAClB;CAUT;AAED,qBAAa,uBAAwB,SAAQ,YAAY;IACvD,SAAiB,IAAI,EAAE,qBAAqB,CAAC;gBAEjC,IAAI,EAAE,qBAAqB,EAAE,OAAO,EAAE,MAAM;CAOzD;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,CAkBpE;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAGzD"}
package/dist/errors.js ADDED
@@ -0,0 +1,65 @@
1
+ function defaultErrorMetadata(code) {
2
+ switch (code) {
3
+ case 'MCP_INVALID_ARGUMENTS':
4
+ case 'MCP_NOT_FOUND':
5
+ case 'MCP_UNKNOWN_TOOL':
6
+ return { category: 'correctable_input', retryable: false, correctable: true };
7
+ case 'MCP_UNAUTHORIZED':
8
+ return { category: 'unauthorized', retryable: false, correctable: false };
9
+ case 'MCP_STALE_CONTRACT':
10
+ return { category: 'stale_contract', retryable: true, correctable: false };
11
+ case 'MCP_REQUEST_CANCELLED':
12
+ case 'MCP_RESULT_TOO_LARGE':
13
+ return { category: 'budget', retryable: false, correctable: false };
14
+ case 'MCP_QUERY_TIMEOUT':
15
+ return { category: 'budget', retryable: true, correctable: false };
16
+ case 'MCP_EXECUTION_FAILED':
17
+ return { category: 'internal', retryable: true, correctable: false };
18
+ }
19
+ }
20
+ export class MCPToolError extends Error {
21
+ code;
22
+ category;
23
+ retryable;
24
+ correctable;
25
+ constructor(code, message, options = {}) {
26
+ super(message);
27
+ const defaults = defaultErrorMetadata(code);
28
+ this.name = 'MCPToolError';
29
+ this.code = code;
30
+ this.category = options.category ?? defaults.category;
31
+ this.retryable = options.retryable ?? defaults.retryable;
32
+ this.correctable = options.correctable ?? defaults.correctable;
33
+ }
34
+ }
35
+ export class MCPExecutionBudgetError extends MCPToolError {
36
+ constructor(code, message) {
37
+ super(code, message, {
38
+ category: 'budget',
39
+ retryable: code === 'MCP_QUERY_TIMEOUT',
40
+ });
41
+ this.name = 'MCPExecutionBudgetError';
42
+ }
43
+ }
44
+ export function classifyMCPToolError(error) {
45
+ if (error instanceof MCPToolError) {
46
+ return {
47
+ code: error.code,
48
+ category: error.category,
49
+ message: error.message,
50
+ retryable: error.retryable,
51
+ correctable: error.correctable,
52
+ };
53
+ }
54
+ return {
55
+ code: 'MCP_EXECUTION_FAILED',
56
+ category: 'internal',
57
+ message: 'Query execution failed',
58
+ retryable: true,
59
+ correctable: false,
60
+ };
61
+ }
62
+ export function formatMCPToolError(error) {
63
+ const classified = classifyMCPToolError(error);
64
+ return `Error [${classified.code}]: ${classified.message}`;
65
+ }
@@ -0,0 +1,50 @@
1
+ import type { CallToolResult, GetPromptResult, ListPromptsResult, ListToolsResult } from '@modelcontextprotocol/sdk/types.js';
2
+ import type { DatasetClient } from '@hypequery/datasets';
3
+ import type { DatasetRegistry, MCPExecutionBudget, MCPQueryLimits } from './types.js';
4
+ export interface MCPExecutorConfig {
5
+ /** Dataset registry - map of dataset names to instances. */
6
+ datasets: DatasetRegistry;
7
+ /** Semantic analytics client for running metric and dataset queries. */
8
+ analytics: DatasetClient;
9
+ /** Trusted tenant id used to scope tenant-keyed datasets. */
10
+ tenantId?: string;
11
+ /** Include generated SQL in trusted-debug responses. Defaults to false. */
12
+ includeSql?: boolean;
13
+ /** Server-side query ceilings applied in addition to Dataset limits. */
14
+ queryLimits?: MCPQueryLimits;
15
+ /** Query deadline and serialized-result byte ceilings. */
16
+ executionBudget?: MCPExecutionBudget;
17
+ }
18
+ export interface MCPServerConfig extends MCPExecutorConfig {
19
+ /** Server name shown to MCP clients. */
20
+ name?: string;
21
+ /** Server version shown to MCP clients. */
22
+ version?: string;
23
+ }
24
+ export interface MCPToolExecutor {
25
+ listTools(): Promise<ListToolsResult>;
26
+ callTool(name: string, args?: Record<string, unknown>, signal?: AbortSignal): Promise<CallToolResult>;
27
+ listPrompts(): Promise<ListPromptsResult>;
28
+ getPrompt(name: string, args?: Record<string, string>): Promise<GetPromptResult>;
29
+ getManifestHash(): string;
30
+ }
31
+ /**
32
+ * Transport-neutral Hypequery MCP tool and prompt executor.
33
+ *
34
+ * This class owns semantic discovery and execution, but has no network or stdio
35
+ * lifecycle. It can be called directly or injected into any MCP transport
36
+ * adapter.
37
+ */
38
+ export declare class HypequeryMCPExecutor implements MCPToolExecutor {
39
+ private readonly config;
40
+ private readonly querySchemas;
41
+ private readonly executionBudget;
42
+ constructor(config: MCPExecutorConfig);
43
+ getManifestHash(): string;
44
+ listTools(): Promise<ListToolsResult>;
45
+ callTool(name: string, args?: Record<string, unknown>, signal?: AbortSignal): Promise<CallToolResult>;
46
+ listPrompts(): Promise<ListPromptsResult>;
47
+ getPrompt(name: string, args?: Record<string, string>): Promise<GetPromptResult>;
48
+ }
49
+ export declare function createMCPExecutor(config: MCPExecutorConfig): HypequeryMCPExecutor;
50
+ //# sourceMappingURL=executor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../src/executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,eAAe,EAChB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EAEV,aAAa,EACd,MAAM,qBAAqB,CAAC;AAe7B,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAOtF,MAAM,WAAW,iBAAiB;IAChC,4DAA4D;IAC5D,QAAQ,EAAE,eAAe,CAAC;IAC1B,wEAAwE;IACxE,SAAS,EAAE,aAAa,CAAC;IACzB,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,wEAAwE;IACxE,WAAW,CAAC,EAAE,cAAc,CAAC;IAC7B,0DAA0D;IAC1D,eAAe,CAAC,EAAE,kBAAkB,CAAC;CACtC;AAED,MAAM,WAAW,eAAgB,SAAQ,iBAAiB;IACxD,wCAAwC;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,IAAI,OAAO,CAAC,eAAe,CAAC,CAAC;IACtC,QAAQ,CACN,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,cAAc,CAAC,CAAC;IAC3B,WAAW,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAC1C,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IACjF,eAAe,IAAI,MAAM,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,qBAAa,oBAAqB,YAAW,eAAe;IAI9C,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHnC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAgC;IAC7D,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA2B;gBAE9B,MAAM,EAAE,iBAAiB;IAOtD,eAAe,IAAI,MAAM;IAInB,SAAS,IAAI,OAAO,CAAC,eAAe,CAAC;IAIrC,QAAQ,CACZ,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,cAAc,CAAC;IAwDpB,WAAW,IAAI,OAAO,CAAC,iBAAiB,CAAC;IAkBzC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,eAAe,CAAC;CAOvF;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,GAAG,oBAAoB,CAEjF"}