@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
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Grains the semantic planner can actually execute. A legacy registry is
3
+ * untyped, so anything outside this set is dropped rather than advertised.
4
+ */
5
+ const TIME_GRAINS = new Set(['day', 'week', 'month', 'quarter', 'year']);
6
+ function record(value) {
7
+ return value !== null && typeof value === 'object' && !Array.isArray(value)
8
+ ? value
9
+ : {};
10
+ }
11
+ function text(value) {
12
+ return typeof value === 'string' && value.length > 0 ? value : undefined;
13
+ }
14
+ function fieldType(value) {
15
+ return value === 'string' || value === 'number' || value === 'boolean' || value === 'timestamp'
16
+ ? value
17
+ : undefined;
18
+ }
19
+ function namedEntries(value) {
20
+ return Object.entries(record(value))
21
+ .map(([name, entry]) => [name, record(entry)])
22
+ .sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0);
23
+ }
24
+ function optionalDescription(value) {
25
+ const label = text(value.label);
26
+ const description = text(value.description);
27
+ return {
28
+ ...(label !== undefined ? { label } : {}),
29
+ ...(description !== undefined ? { description } : {}),
30
+ };
31
+ }
32
+ function semanticMetadata(value) {
33
+ const list = (input) => Array.isArray(input)
34
+ ? [...new Set(input.filter((item) => typeof item === 'string'))].sort()
35
+ : undefined;
36
+ const sensitivity = ['public', 'internal', 'confidential', 'restricted'].includes(String(value.sensitivity))
37
+ ? value.sensitivity
38
+ : undefined;
39
+ return {
40
+ ...(list(value.examples) !== undefined ? { examples: list(value.examples) } : {}),
41
+ ...(list(value.synonyms) !== undefined ? { synonyms: list(value.synonyms) } : {}),
42
+ ...(text(value.format) !== undefined ? { format: text(value.format) } : {}),
43
+ ...(text(value.unit) !== undefined ? { unit: text(value.unit) } : {}),
44
+ ...(/^[A-Z]{3}$/.test(String(value.currency)) ? { currency: String(value.currency) } : {}),
45
+ ...(text(value.timezone) !== undefined ? { timezone: text(value.timezone) } : {}),
46
+ ...(sensitivity !== undefined ? { sensitivity } : {}),
47
+ };
48
+ }
49
+ function limits(value) {
50
+ const input = record(value);
51
+ const result = {};
52
+ for (const key of ['maxDimensions', 'maxMeasures', 'maxFilters', 'maxResultSize']) {
53
+ const candidate = input[key];
54
+ if (Number.isSafeInteger(candidate) && candidate > 0)
55
+ result[key] = candidate;
56
+ }
57
+ return result;
58
+ }
59
+ /** Keeps only the members of `value` that name something the agent may already see. */
60
+ function declaredNames(value, declared) {
61
+ return Array.isArray(value)
62
+ ? [...new Set(value.filter((item) => (typeof item === 'string' && declared.has(item))))].sort()
63
+ : [];
64
+ }
65
+ /** The dimensions a legacy registry entry exposes, in the shape the agent sees. */
66
+ function legacyDimensions(input) {
67
+ return namedEntries(input.dimensions)
68
+ .map(([dimensionName, dimension]) => ({
69
+ name: dimensionName,
70
+ type: fieldType(dimension.fieldType ?? dimension.type),
71
+ ...optionalDescription(dimension),
72
+ ...semanticMetadata(dimension),
73
+ filterable: dimension.filterable !== false,
74
+ groupable: dimension.groupable !== false,
75
+ }))
76
+ .filter((dimension) => (dimension.type !== undefined && (dimension.filterable || dimension.groupable)));
77
+ }
78
+ /**
79
+ * Safely adapts the pre-catalog, object-shaped MCP registry compatibility input.
80
+ *
81
+ * A legacy entry is arbitrary user data, so every name it carries is checked
82
+ * against what this projection already publishes before it is emitted:
83
+ * references that do not resolve to a declared dimension, filter, grain, or
84
+ * sibling dataset are dropped rather than passed through. Otherwise a physical
85
+ * column or tenant key sitting in a legacy `metrics`/`relationships` block
86
+ * would reach the agent through `get_dataset_schema`.
87
+ *
88
+ * `registry` is the surrounding dataset map, used to resolve relationship
89
+ * targets. A relationship whose target is not in it is unreachable, so it is
90
+ * omitted instead of advertising a name the agent cannot query.
91
+ */
92
+ export function projectLegacyAgentDataset(name, input, registry = {}) {
93
+ const config = record(input.config);
94
+ const dimensions = legacyDimensions(input);
95
+ const dimensionTypes = new Map(dimensions.map(dimension => [dimension.name, dimension.type]));
96
+ const dimensionNames = new Set(dimensionTypes.keys());
97
+ const filters = namedEntries(input.filters)
98
+ .map(([filterName, filter]) => ({
99
+ name: filterName,
100
+ type: dimensionTypes.get(text(filter.field) ?? filterName),
101
+ ...optionalDescription(filter),
102
+ ...semanticMetadata(filter),
103
+ operators: Array.isArray(filter.operators)
104
+ ? [...new Set(filter.operators.filter((operator) => typeof operator === 'string'))].sort()
105
+ : [],
106
+ }))
107
+ .filter((filter) => filter.type !== undefined);
108
+ const filterNames = new Set(filters.map(filter => filter.name));
109
+ const timeKey = text(input.timeKey) ?? text(config.timeKey);
110
+ const freshnessInput = record(input.freshness);
111
+ const freshness = Number.isSafeInteger(freshnessInput.maxAgeSeconds)
112
+ && freshnessInput.maxAgeSeconds > 0
113
+ ? { maxAgeSeconds: freshnessInput.maxAgeSeconds }
114
+ : undefined;
115
+ const defaultsInput = record(input.defaults);
116
+ const defaultDimensions = Array.isArray(defaultsInput.dimensions)
117
+ ? declaredNames(defaultsInput.dimensions, dimensionNames)
118
+ : undefined;
119
+ const timeGrain = TIME_GRAINS.has(String(defaultsInput.timeGrain))
120
+ ? defaultsInput.timeGrain
121
+ : undefined;
122
+ const defaults = defaultDimensions !== undefined || timeGrain !== undefined
123
+ ? {
124
+ ...(defaultDimensions !== undefined ? { dimensions: defaultDimensions } : {}),
125
+ ...(timeGrain !== undefined ? { timeGrain } : {}),
126
+ }
127
+ : undefined;
128
+ return {
129
+ name,
130
+ description: text(input.description) ?? text(config.description) ?? `${name} analytics dataset.`,
131
+ ...semanticMetadata(input),
132
+ ...(freshness !== undefined ? { freshness } : {}),
133
+ ...(text(input.owner) !== undefined ? { owner: text(input.owner) } : {}),
134
+ ...(defaults !== undefined ? { defaults } : {}),
135
+ timeDimension: timeKey !== undefined && dimensionNames.has(timeKey) ? timeKey : null,
136
+ dimensions,
137
+ measures: namedEntries(input.measures).map(([measureName, measure]) => ({
138
+ name: measureName,
139
+ ...optionalDescription(measure),
140
+ ...semanticMetadata(measure),
141
+ })),
142
+ metrics: namedEntries(input.metrics).map(([metricName, metric]) => ({
143
+ name: metricName,
144
+ ...optionalDescription(metric),
145
+ ...semanticMetadata(metric),
146
+ dimensions: declaredNames(metric.dimensions, dimensionNames),
147
+ filters: declaredNames(metric.filters, filterNames),
148
+ grains: declaredNames(metric.grains, TIME_GRAINS),
149
+ })),
150
+ filters,
151
+ relationships: namedEntries(input.relationships)
152
+ .filter(([, relationship]) => relationship.queryable !== false && relationship.kind !== 'hasMany')
153
+ .map(([relationshipName, relationship]) => {
154
+ const target = text(relationship.target) ?? text(record(relationship.dataset).name);
155
+ if (target === undefined || !Object.prototype.hasOwnProperty.call(registry, target)) {
156
+ return undefined;
157
+ }
158
+ // A queryable relationship field is exactly `<relationship>.<dimension>`
159
+ // over a single hop, addressing a dimension the target already
160
+ // publishes. See `listQueryableRelationshipFields`.
161
+ const targetDimensions = new Set(legacyDimensions(record(registry[target])).map(dimension => dimension.name));
162
+ return {
163
+ name: relationshipName,
164
+ target,
165
+ fields: declaredNames(relationship.fields, new Set([...targetDimensions].map(field => `${relationshipName}.${field}`))),
166
+ };
167
+ })
168
+ .filter((relationship) => (relationship !== undefined)),
169
+ limits: limits(input.limits),
170
+ };
171
+ }
@@ -0,0 +1,25 @@
1
+ import { type MCPQueryLimits } from '../../types.js';
2
+ interface QueryCollections {
3
+ readonly dimensions?: readonly unknown[];
4
+ readonly measures?: readonly unknown[];
5
+ readonly filters?: readonly unknown[];
6
+ readonly orderBy?: readonly unknown[];
7
+ readonly limit?: number;
8
+ readonly offset?: number;
9
+ }
10
+ export interface EffectiveQueryLimits {
11
+ readonly defaultResultSize: number;
12
+ readonly maxResultSize: number;
13
+ readonly maxOffset: number;
14
+ readonly maxDimensions: number;
15
+ readonly maxMeasures: number;
16
+ readonly maxFilters: number;
17
+ readonly maxOrderBy: number;
18
+ }
19
+ export declare function resolveQueryLimits(dataset: unknown, configured?: MCPQueryLimits): EffectiveQueryLimits;
20
+ export declare function applyQueryLimits(dataset: unknown, query: QueryCollections, configured?: MCPQueryLimits): {
21
+ readonly limit: number;
22
+ readonly offset?: number;
23
+ };
24
+ export {};
25
+ //# sourceMappingURL=query-limits.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-limits.d.ts","sourceRoot":"","sources":["../../../src/tools/utils/query-limits.ts"],"names":[],"mappings":"AAEA,OAAO,EAQL,KAAK,cAAc,EACpB,MAAM,gBAAgB,CAAC;AAExB,UAAU,gBAAgB;IACxB,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;IACzC,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;IACvC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;IACtC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;IACtC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAsCD,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,OAAO,EAChB,UAAU,GAAE,cAAmB,GAC9B,oBAAoB,CAkCtB;AAeD,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,gBAAgB,EACvB,UAAU,GAAE,cAAmB,GAC9B;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAqBtD"}
@@ -0,0 +1,69 @@
1
+ import { MCPToolError } from '../../errors.js';
2
+ import { DEFAULT_QUERY_LIMIT, MAX_QUERY_DIMENSIONS, MAX_QUERY_FILTERS, MAX_QUERY_LIMIT, MAX_QUERY_MEASURES, MAX_QUERY_OFFSET, MAX_QUERY_ORDER_BY, } from '../../types.js';
3
+ function positiveInteger(value, fallback, maximum, name) {
4
+ const resolved = value ?? fallback;
5
+ if (!Number.isSafeInteger(resolved) || resolved < 1 || resolved > maximum) {
6
+ throw new Error(`${name} must be an integer between 1 and ${maximum}`);
7
+ }
8
+ return resolved;
9
+ }
10
+ function nonNegativeInteger(value, fallback, maximum, name) {
11
+ const resolved = value ?? fallback;
12
+ if (!Number.isSafeInteger(resolved) || resolved < 0 || resolved > maximum) {
13
+ throw new Error(`${name} must be an integer between 0 and ${maximum}`);
14
+ }
15
+ return resolved;
16
+ }
17
+ function datasetLimits(dataset) {
18
+ if (!dataset || typeof dataset !== 'object' || Array.isArray(dataset))
19
+ return undefined;
20
+ const limits = dataset.limits;
21
+ return limits && typeof limits === 'object' && !Array.isArray(limits)
22
+ ? limits
23
+ : undefined;
24
+ }
25
+ function datasetPositiveInteger(value, name) {
26
+ if (value === undefined)
27
+ return undefined;
28
+ if (!Number.isSafeInteger(value) || value < 1) {
29
+ throw new Error(`Dataset ${name} must be a positive integer`);
30
+ }
31
+ return value;
32
+ }
33
+ function lowerLimit(...values) {
34
+ return Math.min(...values.filter((value) => value !== undefined));
35
+ }
36
+ export function resolveQueryLimits(dataset, configured = {}) {
37
+ const semantic = datasetLimits(dataset);
38
+ const maxResultSize = lowerLimit(positiveInteger(configured.maxResultSize, MAX_QUERY_LIMIT, MAX_QUERY_LIMIT, 'maxResultSize'), datasetPositiveInteger(semantic?.maxResultSize, 'maxResultSize'));
39
+ const defaultResultSize = lowerLimit(positiveInteger(configured.defaultResultSize, DEFAULT_QUERY_LIMIT, MAX_QUERY_LIMIT, 'defaultResultSize'), maxResultSize);
40
+ return Object.freeze({
41
+ defaultResultSize,
42
+ maxResultSize,
43
+ maxOffset: nonNegativeInteger(configured.maxOffset, MAX_QUERY_OFFSET, MAX_QUERY_OFFSET, 'maxOffset'),
44
+ maxDimensions: lowerLimit(positiveInteger(configured.maxDimensions, MAX_QUERY_DIMENSIONS, MAX_QUERY_DIMENSIONS, 'maxDimensions'), datasetPositiveInteger(semantic?.maxDimensions, 'maxDimensions')),
45
+ maxMeasures: lowerLimit(positiveInteger(configured.maxMeasures, MAX_QUERY_MEASURES, MAX_QUERY_MEASURES, 'maxMeasures'), datasetPositiveInteger(semantic?.maxMeasures, 'maxMeasures')),
46
+ maxFilters: lowerLimit(positiveInteger(configured.maxFilters, MAX_QUERY_FILTERS, MAX_QUERY_FILTERS, 'maxFilters'), datasetPositiveInteger(semantic?.maxFilters, 'maxFilters')),
47
+ maxOrderBy: positiveInteger(configured.maxOrderBy, MAX_QUERY_ORDER_BY, MAX_QUERY_ORDER_BY, 'maxOrderBy'),
48
+ });
49
+ }
50
+ function assertCollectionLimit(values, maximum, name) {
51
+ if ((values?.length ?? 0) > maximum) {
52
+ throw new MCPToolError('MCP_INVALID_ARGUMENTS', `Invalid ${name}: maximum ${maximum} items`);
53
+ }
54
+ }
55
+ export function applyQueryLimits(dataset, query, configured = {}) {
56
+ const limits = resolveQueryLimits(dataset, configured);
57
+ assertCollectionLimit(query.dimensions, limits.maxDimensions, 'dimensions');
58
+ assertCollectionLimit(query.measures, limits.maxMeasures, 'measures');
59
+ assertCollectionLimit(query.filters, limits.maxFilters, 'filters');
60
+ assertCollectionLimit(query.orderBy, limits.maxOrderBy, 'orderBy');
61
+ const limit = query.limit ?? limits.defaultResultSize;
62
+ if (limit > limits.maxResultSize) {
63
+ throw new MCPToolError('MCP_INVALID_ARGUMENTS', `Invalid limit: ${limit}. Max: ${limits.maxResultSize}`);
64
+ }
65
+ if (query.offset !== undefined && query.offset > limits.maxOffset) {
66
+ throw new MCPToolError('MCP_INVALID_ARGUMENTS', `Invalid offset: ${query.offset}. Max: ${limits.maxOffset}`);
67
+ }
68
+ return Object.freeze({ limit, ...(query.offset === undefined ? {} : { offset: query.offset }) });
69
+ }
@@ -0,0 +1,4 @@
1
+ import type { DatasetQueryResult } from '@hypequery/datasets';
2
+ import type { QueryResultResponse } from '../../types.js';
3
+ export declare function buildMCPQueryResult(result: DatasetQueryResult, includeSql?: boolean): QueryResultResponse;
4
+ //# sourceMappingURL=query-result.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-result.d.ts","sourceRoot":"","sources":["../../../src/tools/utils/query-result.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE1D,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,kBAAkB,EAC1B,UAAU,UAAQ,GACjB,mBAAmB,CAkBrB"}
@@ -0,0 +1,19 @@
1
+ export function buildMCPQueryResult(result, includeSql = false) {
2
+ const cache = result.meta?.cache;
3
+ return {
4
+ data: result.data,
5
+ meta: {
6
+ ...(includeSql && result.meta?.sql ? { sql: result.meta.sql } : {}),
7
+ ...(result.meta?.timingMs === undefined ? {} : { timingMs: result.meta.timingMs }),
8
+ rowCount: result.data.length,
9
+ ...(result.meta?.pagination ? { pagination: result.meta.pagination } : {}),
10
+ cache: cache
11
+ ? {
12
+ status: cache.hit ? 'hit' : 'miss',
13
+ ...(cache.ageMs === undefined ? {} : { ageMs: cache.ageMs }),
14
+ ...(cache.stale === undefined ? {} : { stale: cache.stale }),
15
+ }
16
+ : { status: 'bypass' },
17
+ },
18
+ };
19
+ }
@@ -0,0 +1,8 @@
1
+ import type { DatasetRegistry, MCPQueryLimits } from '../../types.js';
2
+ export type JsonObject = Record<string, unknown>;
3
+ /**
4
+ * Builds a dataset-discriminated query schema that advertises each dataset's
5
+ * effective server and semantic-layer limits to MCP clients.
6
+ */
7
+ export declare function advertiseDatasetQueryLimits(schema: JsonObject, datasets: DatasetRegistry, configured: MCPQueryLimits | undefined, includeMeasures: boolean): JsonObject;
8
+ //# sourceMappingURL=query-schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-schema.d.ts","sourceRoot":"","sources":["../../../src/tools/utils/query-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAGtE,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEjD;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,UAAU,EAClB,QAAQ,EAAE,eAAe,EACzB,UAAU,EAAE,cAAc,GAAG,SAAS,EACtC,eAAe,EAAE,OAAO,GACvB,UAAU,CA8BZ"}
@@ -0,0 +1,36 @@
1
+ import { resolveQueryLimits } from './query-limits.js';
2
+ /**
3
+ * Builds a dataset-discriminated query schema that advertises each dataset's
4
+ * effective server and semantic-layer limits to MCP clients.
5
+ */
6
+ export function advertiseDatasetQueryLimits(schema, datasets, configured, includeMeasures) {
7
+ const entries = Object.entries(datasets);
8
+ if (entries.length === 0)
9
+ return schema;
10
+ const properties = schema.properties;
11
+ return {
12
+ type: 'object',
13
+ anyOf: entries.map(([name, dataset]) => {
14
+ const limits = resolveQueryLimits(dataset, configured);
15
+ return {
16
+ ...schema,
17
+ properties: {
18
+ ...properties,
19
+ dataset: { ...properties.dataset, enum: [name] },
20
+ dimensions: { ...properties.dimensions, maxItems: limits.maxDimensions },
21
+ ...(includeMeasures ? {
22
+ measures: { ...properties.measures, maxItems: limits.maxMeasures },
23
+ } : {}),
24
+ filters: { ...properties.filters, maxItems: limits.maxFilters },
25
+ orderBy: { ...properties.orderBy, maxItems: limits.maxOrderBy },
26
+ limit: {
27
+ ...properties.limit,
28
+ maximum: limits.maxResultSize,
29
+ default: limits.defaultResultSize,
30
+ },
31
+ offset: { ...properties.offset, maximum: limits.maxOffset },
32
+ },
33
+ };
34
+ }),
35
+ };
36
+ }
@@ -0,0 +1,6 @@
1
+ import type { MCPToolResponse } from '../../types.js';
2
+ export declare function createMCPToolResponse<T extends object>(value: T, text?: string): MCPToolResponse;
3
+ export declare function createMCPErrorResponse(error: unknown): MCPToolResponse;
4
+ /** Smallest schema-valid error used when even the original error exceeds its budget. */
5
+ export declare function createMCPResultTooLargeResponse(): MCPToolResponse;
6
+ //# sourceMappingURL=tool-response.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-response.d.ts","sourceRoot":"","sources":["../../../src/tools/utils/tool-response.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtD,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,MAAM,EACpD,KAAK,EAAE,CAAC,EACR,IAAI,SAAwB,GAC3B,eAAe,CAKjB;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,CAOtE;AAED,wFAAwF;AACxF,wBAAgB,+BAA+B,IAAI,eAAe,CAgBjE"}
@@ -0,0 +1,33 @@
1
+ import { classifyMCPToolError, formatMCPToolError } from '../../errors.js';
2
+ export function createMCPToolResponse(value, text = JSON.stringify(value)) {
3
+ return {
4
+ content: [{ type: 'text', text }],
5
+ structuredContent: value,
6
+ };
7
+ }
8
+ export function createMCPErrorResponse(error) {
9
+ const details = classifyMCPToolError(error);
10
+ return {
11
+ content: [{ type: 'text', text: formatMCPToolError(error) }],
12
+ structuredContent: { error: details },
13
+ isError: true,
14
+ };
15
+ }
16
+ /** Smallest schema-valid error used when even the original error exceeds its budget. */
17
+ export function createMCPResultTooLargeResponse() {
18
+ const details = {
19
+ code: 'MCP_RESULT_TOO_LARGE',
20
+ category: 'budget',
21
+ message: 'Result exceeds response byte limit',
22
+ retryable: false,
23
+ correctable: false,
24
+ };
25
+ return {
26
+ content: [{
27
+ type: 'text',
28
+ text: `Error [${details.code}]: ${details.message}`,
29
+ }],
30
+ structuredContent: { error: details },
31
+ isError: true,
32
+ };
33
+ }
package/dist/types.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Type definitions for MCP Server
3
3
  */
4
- import type { AnyDatasetInstance, MetricFilter, TimeGrain, MetricOrderBy } from '@hypequery/datasets';
4
+ import type { AgentCatalogDataset, AgentCatalogDimension, AgentCatalogFilter, AgentCatalogMeasure, AgentCatalogMetric, AgentCatalogRelationship, AnyDatasetInstance, MetricFilter, TimeGrain, MetricOrderBy } from '@hypequery/datasets';
5
+ import type { ZodTypeAny } from 'zod';
5
6
  /**
6
7
  * Registry of datasets - maps dataset names to dataset instances
7
8
  */
@@ -35,8 +36,38 @@ export interface QueryDatasetArgs {
35
36
  export interface QueryToolOptions {
36
37
  tenantId?: string;
37
38
  includeSql?: boolean;
39
+ limits?: MCPQueryLimits;
40
+ executionBudget?: MCPExecutionBudget;
41
+ signal?: AbortSignal;
42
+ /** Canonical catalog-derived validator supplied by the owning server. */
43
+ inputSchema?: ZodTypeAny;
44
+ }
45
+ /** Per-query wall-clock and serialized-response ceilings. */
46
+ export interface MCPExecutionBudget {
47
+ /** Maximum query duration in milliseconds. Defaults to 30 seconds. */
48
+ timeoutMs?: number;
49
+ /** Maximum UTF-8 bytes in the serialized query response. Defaults to 1 MiB. */
50
+ maxResponseBytes?: number;
51
+ }
52
+ /** Server-side ceilings applied in addition to Dataset limits. */
53
+ export interface MCPQueryLimits {
54
+ /** Rows used when a tool call omits `limit`. Defaults to 100. */
55
+ defaultResultSize?: number;
56
+ /** Maximum explicit or default row limit. Cannot exceed 10,000. */
57
+ maxResultSize?: number;
58
+ /** Maximum pagination offset. Cannot exceed 10,000. */
59
+ maxOffset?: number;
60
+ /** Maximum selected dimensions. Cannot exceed 50. */
61
+ maxDimensions?: number;
62
+ /** Maximum selected measures. Cannot exceed 50. */
63
+ maxMeasures?: number;
64
+ /** Maximum filters. Cannot exceed 100. */
65
+ maxFilters?: number;
66
+ /** Maximum order clauses. Cannot exceed 50. */
67
+ maxOrderBy?: number;
38
68
  }
39
69
  export interface SchemaToolOptions {
70
+ /** @deprecated Agent-facing introspection is always safe. Use getTrustedDatasetSchema separately. */
40
71
  includeSql?: boolean;
41
72
  }
42
73
  /**
@@ -54,84 +85,34 @@ export interface MCPToolResponse {
54
85
  type: 'text';
55
86
  text: string;
56
87
  }>;
88
+ structuredContent?: Record<string, unknown>;
57
89
  isError?: boolean;
58
90
  [key: string]: unknown;
59
91
  }
60
92
  /**
61
93
  * Dataset schema response structure
62
94
  */
63
- export interface DatasetSchema {
64
- name: string;
65
- description: string;
66
- source: string;
67
- timeKey: string | null;
68
- tenantKey: string | null;
69
- dimensions: Record<string, DimensionSchema>;
70
- measures: Record<string, MeasureSchema>;
71
- metrics: Record<string, MetricSchema>;
72
- filters: Record<string, FilterSchema>;
73
- relationships: Record<string, RelationshipSchema>;
74
- limits?: {
75
- maxDimensions?: number;
76
- maxMeasures?: number;
77
- maxFilters?: number;
78
- maxResultSize?: number;
79
- };
80
- }
95
+ export type DatasetSchema = AgentCatalogDataset;
81
96
  /**
82
97
  * Dimension schema in response
83
98
  */
84
- export interface DimensionSchema {
85
- type: string;
86
- column: string | null;
87
- sql: string | null;
88
- label: string;
89
- description: string;
90
- examples: string[];
91
- filterable: boolean;
92
- groupable: boolean;
93
- }
99
+ export type DimensionSchema = AgentCatalogDimension;
94
100
  /**
95
101
  * Measure schema in response
96
102
  */
97
- export interface MeasureSchema {
98
- aggregation: string;
99
- field: string;
100
- sql: string | null;
101
- label: string;
102
- description: string;
103
- }
103
+ export type MeasureSchema = AgentCatalogMeasure;
104
104
  /**
105
105
  * Filter schema in response
106
106
  */
107
- export interface FilterSchema {
108
- field: string;
109
- label: string;
110
- description: string;
111
- operators: string[] | null;
112
- }
107
+ export type FilterSchema = AgentCatalogFilter;
113
108
  /**
114
109
  * Metric schema in response
115
110
  */
116
- export interface MetricSchema {
117
- type: string;
118
- aggregation: string;
119
- label: string;
120
- description: string;
121
- format: string | null;
122
- }
111
+ export type MetricSchema = AgentCatalogMetric;
123
112
  /**
124
113
  * Relationship schema in response
125
114
  */
126
- export interface RelationshipSchema {
127
- type: string;
128
- target: string;
129
- from?: string;
130
- to?: string;
131
- queryable?: boolean;
132
- fields?: string[];
133
- description: string;
134
- }
115
+ export type RelationshipSchema = AgentCatalogRelationship;
135
116
  /**
136
117
  * Dataset list item
137
118
  */
@@ -165,6 +146,12 @@ export interface QueryResultMeta {
165
146
  offset: number;
166
147
  hasMore: boolean;
167
148
  };
149
+ /** Cache outcome for agent observability. */
150
+ cache?: {
151
+ status: 'hit' | 'miss' | 'bypass';
152
+ ageMs?: number;
153
+ stale?: boolean;
154
+ };
168
155
  }
169
156
  /**
170
157
  * Query result response
@@ -178,4 +165,13 @@ export interface QueryResultResponse {
178
165
  */
179
166
  export declare const MAX_QUERY_LIMIT = 10000;
180
167
  export declare const DEFAULT_QUERY_LIMIT = 100;
168
+ export declare const MAX_QUERY_OFFSET = 10000;
169
+ export declare const MAX_QUERY_DIMENSIONS = 50;
170
+ export declare const MAX_QUERY_MEASURES = 50;
171
+ export declare const MAX_QUERY_FILTERS = 100;
172
+ export declare const MAX_QUERY_ORDER_BY = 50;
173
+ export declare const DEFAULT_QUERY_TIMEOUT_MS = 30000;
174
+ export declare const MAX_QUERY_TIMEOUT_MS = 120000;
175
+ export declare const DEFAULT_RESPONSE_BYTES = 1048576;
176
+ export declare const MAX_RESPONSE_BYTES = 10485760;
181
177
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js CHANGED
@@ -6,3 +6,12 @@
6
6
  */
7
7
  export const MAX_QUERY_LIMIT = 10000;
8
8
  export const DEFAULT_QUERY_LIMIT = 100;
9
+ export const MAX_QUERY_OFFSET = 10000;
10
+ export const MAX_QUERY_DIMENSIONS = 50;
11
+ export const MAX_QUERY_MEASURES = 50;
12
+ export const MAX_QUERY_FILTERS = 100;
13
+ export const MAX_QUERY_ORDER_BY = 50;
14
+ export const DEFAULT_QUERY_TIMEOUT_MS = 30_000;
15
+ export const MAX_QUERY_TIMEOUT_MS = 120_000;
16
+ export const DEFAULT_RESPONSE_BYTES = 1_048_576;
17
+ export const MAX_RESPONSE_BYTES = 10_485_760;
@@ -0,0 +1,3 @@
1
+ import type { MCPExecutorConfig } from '../executor.js';
2
+ export declare function validateMCPServerTenantConfig(config: MCPExecutorConfig): void;
3
+ //# sourceMappingURL=tenant-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tenant-config.d.ts","sourceRoot":"","sources":["../../src/utils/tenant-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAiBxD,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAc7E"}
@@ -0,0 +1,23 @@
1
+ function isRecord(value) {
2
+ return !!value && typeof value === 'object';
3
+ }
4
+ function getTenantKey(dataset) {
5
+ if (!isRecord(dataset)) {
6
+ return undefined;
7
+ }
8
+ const config = dataset.config;
9
+ const configTenantKey = isRecord(config) ? config.tenantKey : undefined;
10
+ const tenantKey = dataset.tenantKey ?? configTenantKey;
11
+ return typeof tenantKey === 'string' && tenantKey.length > 0 ? tenantKey : undefined;
12
+ }
13
+ export function validateMCPServerTenantConfig(config) {
14
+ if (config.tenantId) {
15
+ return;
16
+ }
17
+ const tenantScopedDatasets = Object.entries(config.datasets ?? {})
18
+ .filter(([, dataset]) => getTenantKey(dataset))
19
+ .map(([name]) => name);
20
+ if (tenantScopedDatasets.length > 0) {
21
+ throw new Error(`MCP server tenantId is required for tenant-scoped datasets: ${tenantScopedDatasets.join(', ')}`);
22
+ }
23
+ }
@@ -0,0 +1,2 @@
1
+ export declare const MCP_PACKAGE_VERSION = "0.6.0";
2
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,mBAAmB,UAAU,CAAC"}
@@ -0,0 +1,5 @@
1
+ // Generated by scripts/generate-version.mjs. Do not edit.
2
+ //
3
+ // Resolved at build time rather than read from package.json at import time, so
4
+ // importing this package touches no filesystem and survives bundling.
5
+ export const MCP_PACKAGE_VERSION = '0.6.0';