@hypequery/mcp 0.6.0 → 0.7.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/dist/discovery-executor.d.ts +78 -0
- package/dist/discovery-executor.d.ts.map +1 -0
- package/dist/discovery-executor.js +111 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/tools/utils/canonical-query-schemas.d.ts +9 -1
- package/dist/tools/utils/canonical-query-schemas.d.ts.map +1 -1
- package/dist/tools/utils/canonical-query-schemas.js +35 -12
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discovery without execution.
|
|
3
|
+
*
|
|
4
|
+
* A hosted gateway lists tools for one principal against one activated
|
|
5
|
+
* deployment, and does that before — and independently of — being able to run
|
|
6
|
+
* anything. `HypequeryMCPExecutor` cannot serve that: it requires a
|
|
7
|
+
* `DatasetClient` it would never call, and refuses to construct at all when a
|
|
8
|
+
* dataset is tenant-scoped and no fixed `tenantId` is configured. Both are
|
|
9
|
+
* correct for a local server, where one process serves one tenant and every
|
|
10
|
+
* listed tool is runnable. Neither holds for a gateway, which resolves a tenant
|
|
11
|
+
* per request through the deployment data plane.
|
|
12
|
+
*
|
|
13
|
+
* The alternative would be a second manifest generator in the gateway, which
|
|
14
|
+
* `CORE-03` exists to prevent: the tool schemas an agent is given and the
|
|
15
|
+
* validators a query is checked against have to come from one catalog.
|
|
16
|
+
*
|
|
17
|
+
* So this shares the schema compiler and the catalog tools, and refuses the two
|
|
18
|
+
* tools that need a query engine. Listing a tool it will not run is deliberate:
|
|
19
|
+
* the manifest a client caches must be the one it will keep seeing once
|
|
20
|
+
* execution is wired in behind it, or every client re-lists on the day that
|
|
21
|
+
* lands.
|
|
22
|
+
*/
|
|
23
|
+
import type { CallToolResult, GetPromptResult, ListPromptsResult, ListToolsResult } from '@modelcontextprotocol/sdk/types.js';
|
|
24
|
+
import type { MCPToolExecutor } from './executor.js';
|
|
25
|
+
import type { DatasetRegistry, MCPQueryLimits } from './types.js';
|
|
26
|
+
/**
|
|
27
|
+
* Provenance a client needs to cache a manifest and know when it went stale.
|
|
28
|
+
*
|
|
29
|
+
* Namespaced under `com.hypequery/` in the result's `_meta`, as the MCP spec
|
|
30
|
+
* requires of implementation-defined keys.
|
|
31
|
+
*/
|
|
32
|
+
export interface MCPToolManifestMeta {
|
|
33
|
+
/** The immutable generation these tools were listed from. */
|
|
34
|
+
readonly activationRevision?: string;
|
|
35
|
+
/** Content-addressed identity of the contract behind them. */
|
|
36
|
+
readonly deploymentIdentity?: string;
|
|
37
|
+
/** How the tools were shaped — `catalog` for the fixed compatibility set. */
|
|
38
|
+
readonly toolMode?: string;
|
|
39
|
+
}
|
|
40
|
+
export interface MCPDiscoveryExecutorConfig {
|
|
41
|
+
/** Datasets to advertise. Already narrowed to what the caller may see. */
|
|
42
|
+
datasets: DatasetRegistry;
|
|
43
|
+
/**
|
|
44
|
+
* Datasets offered as a `query_dataset` target. Defaults to all of them.
|
|
45
|
+
*
|
|
46
|
+
* A deployment authorizes a dataset and each of its metrics through separate
|
|
47
|
+
* endpoint policies, so a caller can be entitled to a metric on a dataset it
|
|
48
|
+
* may not query directly. Such a dataset still belongs in `datasets` — its
|
|
49
|
+
* metrics are reachable, and it may be joined to — but naming it here would
|
|
50
|
+
* advertise a target execution refuses.
|
|
51
|
+
*/
|
|
52
|
+
queryableDatasets?: readonly string[];
|
|
53
|
+
/** Server-side query ceilings, so advertised schemas match what will run. */
|
|
54
|
+
queryLimits?: MCPQueryLimits;
|
|
55
|
+
/** Attached to `listTools`, so a client can pin what it listed. */
|
|
56
|
+
meta?: MCPToolManifestMeta;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* A read-only executor over a catalog.
|
|
60
|
+
*
|
|
61
|
+
* `list_datasets`, `get_dataset_schema`, and the prompts read the agent-safe
|
|
62
|
+
* catalog and need no query engine, so they answer normally. `query_dataset`
|
|
63
|
+
* and `query_metric` are advertised with their exact schemas and refuse.
|
|
64
|
+
*/
|
|
65
|
+
export declare class HypequeryMCPDiscoveryExecutor implements MCPToolExecutor {
|
|
66
|
+
private readonly config;
|
|
67
|
+
private readonly querySchemas;
|
|
68
|
+
private readonly meta;
|
|
69
|
+
constructor(config: MCPDiscoveryExecutorConfig);
|
|
70
|
+
/** The catalog these tools were compiled from, for caching by content. */
|
|
71
|
+
getManifestHash(): string;
|
|
72
|
+
listTools(): Promise<ListToolsResult>;
|
|
73
|
+
callTool(name: string, args?: Record<string, unknown>): Promise<CallToolResult>;
|
|
74
|
+
listPrompts(): Promise<ListPromptsResult>;
|
|
75
|
+
getPrompt(name: string, args?: Record<string, string>): Promise<GetPromptResult>;
|
|
76
|
+
}
|
|
77
|
+
export declare function createMCPDiscoveryExecutor(config: MCPDiscoveryExecutorConfig): MCPToolExecutor;
|
|
78
|
+
//# sourceMappingURL=discovery-executor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery-executor.d.ts","sourceRoot":"","sources":["../src/discovery-executor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,eAAe,EAChB,MAAM,oCAAoC,CAAC;AAG5C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAOrD,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAElE;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IAClC,6DAA6D;IAC7D,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC,8DAA8D;IAC9D,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC,6EAA6E;IAC7E,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,0BAA0B;IACzC,0EAA0E;IAC1E,QAAQ,EAAE,eAAe,CAAC;IAC1B;;;;;;;;OAQG;IACH,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,6EAA6E;IAC7E,WAAW,CAAC,EAAE,cAAc,CAAC;IAC7B,mEAAmE;IACnE,IAAI,CAAC,EAAE,mBAAmB,CAAC;CAC5B;AAeD;;;;;;GAMG;AACH,qBAAa,6BAA8B,YAAW,eAAe;IAIvD,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHnC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAgC;IAC7D,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAqC;gBAE7B,MAAM,EAAE,0BAA0B;IAW/D,0EAA0E;IAC1E,eAAe,IAAI,MAAM;IAInB,SAAS,IAAI,OAAO,CAAC,eAAe,CAAC;IAKrC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,cAAc,CAAC;IAyB/E,WAAW,IAAI,OAAO,CAAC,iBAAiB,CAAC;IAczC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,eAAe,CAAC;CAMvF;AAED,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,0BAA0B,GACjC,eAAe,CAEjB"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discovery without execution.
|
|
3
|
+
*
|
|
4
|
+
* A hosted gateway lists tools for one principal against one activated
|
|
5
|
+
* deployment, and does that before — and independently of — being able to run
|
|
6
|
+
* anything. `HypequeryMCPExecutor` cannot serve that: it requires a
|
|
7
|
+
* `DatasetClient` it would never call, and refuses to construct at all when a
|
|
8
|
+
* dataset is tenant-scoped and no fixed `tenantId` is configured. Both are
|
|
9
|
+
* correct for a local server, where one process serves one tenant and every
|
|
10
|
+
* listed tool is runnable. Neither holds for a gateway, which resolves a tenant
|
|
11
|
+
* per request through the deployment data plane.
|
|
12
|
+
*
|
|
13
|
+
* The alternative would be a second manifest generator in the gateway, which
|
|
14
|
+
* `CORE-03` exists to prevent: the tool schemas an agent is given and the
|
|
15
|
+
* validators a query is checked against have to come from one catalog.
|
|
16
|
+
*
|
|
17
|
+
* So this shares the schema compiler and the catalog tools, and refuses the two
|
|
18
|
+
* tools that need a query engine. Listing a tool it will not run is deliberate:
|
|
19
|
+
* the manifest a client caches must be the one it will keep seeing once
|
|
20
|
+
* execution is wired in behind it, or every client re-lists on the day that
|
|
21
|
+
* lands.
|
|
22
|
+
*/
|
|
23
|
+
import { MCPToolError } from './errors.js';
|
|
24
|
+
import { datasetGuidePrompt } from './prompts/dataset-guide.js';
|
|
25
|
+
import { getDatasetSchemaTool } from './tools/introspect.js';
|
|
26
|
+
import { listDatasetsTool } from './tools/list-datasets.js';
|
|
27
|
+
import { buildMCPToolManifest } from './tools/tool-manifest.js';
|
|
28
|
+
import { buildMCPQuerySchemas } from './tools/utils/canonical-query-schemas.js';
|
|
29
|
+
import { createMCPErrorResponse } from './tools/utils/tool-response.js';
|
|
30
|
+
const NOT_EXECUTABLE = 'This endpoint lists datasets and metrics but does not execute queries.';
|
|
31
|
+
function metaEntries(meta) {
|
|
32
|
+
if (meta === undefined)
|
|
33
|
+
return undefined;
|
|
34
|
+
const entries = Object.entries({
|
|
35
|
+
'com.hypequery/activationRevision': meta.activationRevision,
|
|
36
|
+
'com.hypequery/deploymentIdentity': meta.deploymentIdentity,
|
|
37
|
+
'com.hypequery/toolMode': meta.toolMode,
|
|
38
|
+
}).filter((entry) => entry[1] !== undefined);
|
|
39
|
+
return entries.length === 0 ? undefined : Object.fromEntries(entries);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* A read-only executor over a catalog.
|
|
43
|
+
*
|
|
44
|
+
* `list_datasets`, `get_dataset_schema`, and the prompts read the agent-safe
|
|
45
|
+
* catalog and need no query engine, so they answer normally. `query_dataset`
|
|
46
|
+
* and `query_metric` are advertised with their exact schemas and refuse.
|
|
47
|
+
*/
|
|
48
|
+
export class HypequeryMCPDiscoveryExecutor {
|
|
49
|
+
config;
|
|
50
|
+
querySchemas;
|
|
51
|
+
meta;
|
|
52
|
+
constructor(config) {
|
|
53
|
+
this.config = config;
|
|
54
|
+
// Deliberately no tenant assertion. A gateway has no fixed tenant to
|
|
55
|
+
// declare, and none is needed: nothing here reaches a table.
|
|
56
|
+
this.querySchemas = buildMCPQuerySchemas(config.datasets ?? {}, config.queryLimits, config.queryableDatasets);
|
|
57
|
+
this.meta = metaEntries(config.meta);
|
|
58
|
+
}
|
|
59
|
+
/** The catalog these tools were compiled from, for caching by content. */
|
|
60
|
+
getManifestHash() {
|
|
61
|
+
return this.querySchemas.manifestHash;
|
|
62
|
+
}
|
|
63
|
+
async listTools() {
|
|
64
|
+
const manifest = buildMCPToolManifest(this.querySchemas);
|
|
65
|
+
return this.meta === undefined ? manifest : { ...manifest, _meta: this.meta };
|
|
66
|
+
}
|
|
67
|
+
async callTool(name, args) {
|
|
68
|
+
try {
|
|
69
|
+
switch (name) {
|
|
70
|
+
case 'list_datasets':
|
|
71
|
+
return await listDatasetsTool(this.config.datasets);
|
|
72
|
+
case 'get_dataset_schema':
|
|
73
|
+
return await getDatasetSchemaTool(this.config.datasets, args);
|
|
74
|
+
case 'query_dataset':
|
|
75
|
+
case 'query_metric':
|
|
76
|
+
// Not `MCP_UNKNOWN_TOOL`: the tool exists and is listed, and telling a
|
|
77
|
+
// client it does not would invite it to stop asking for good.
|
|
78
|
+
throw new MCPToolError('MCP_EXECUTION_FAILED', NOT_EXECUTABLE, {
|
|
79
|
+
retryable: false,
|
|
80
|
+
});
|
|
81
|
+
default:
|
|
82
|
+
throw new MCPToolError('MCP_UNKNOWN_TOOL', `Unknown tool: ${name}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
return createMCPErrorResponse(error);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async listPrompts() {
|
|
90
|
+
return {
|
|
91
|
+
prompts: [{
|
|
92
|
+
name: 'dataset_guide',
|
|
93
|
+
description: 'Guide for querying datasets with natural language',
|
|
94
|
+
arguments: [{
|
|
95
|
+
name: 'dataset',
|
|
96
|
+
description: 'Name of the dataset to get guidance for',
|
|
97
|
+
required: false,
|
|
98
|
+
}],
|
|
99
|
+
}],
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
async getPrompt(name, args) {
|
|
103
|
+
if (name === 'dataset_guide') {
|
|
104
|
+
return datasetGuidePrompt(this.config.datasets, args?.dataset);
|
|
105
|
+
}
|
|
106
|
+
throw new Error(`Unknown prompt: ${name}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
export function createMCPDiscoveryExecutor(config) {
|
|
110
|
+
return new HypequeryMCPDiscoveryExecutor(config);
|
|
111
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export { HypequeryMCPServer, createMCPServer, type MCPServerConfig } from './server.js';
|
|
8
8
|
export { HypequeryMCPExecutor, createMCPExecutor, type MCPExecutorConfig, type MCPToolExecutor, } from './executor.js';
|
|
9
|
+
export { HypequeryMCPDiscoveryExecutor, createMCPDiscoveryExecutor, type MCPDiscoveryExecutorConfig, type MCPToolManifestMeta, } from './discovery-executor.js';
|
|
9
10
|
export { HypequeryMCPProtocolServer, createMCPProtocolServer, type MCPProtocolServerOptions, } from './protocol-server.js';
|
|
10
11
|
export { connectMCPServerStdio, startStdioMCPServer } from './stdio.js';
|
|
11
12
|
export { listDatasetsTool } from './tools/list-datasets.js';
|
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,EACL,oBAAoB,EACpB,iBAAiB,EACjB,KAAK,iBAAiB,EACtB,KAAK,eAAe,GACrB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,0BAA0B,EAC1B,uBAAuB,EACvB,KAAK,wBAAwB,GAC9B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AACtF,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,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,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,EACL,uBAAuB,EACvB,YAAY,EACZ,oBAAoB,EACpB,kBAAkB,EAClB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,GAC1B,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,gBAAgB,EAChB,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,wBAAwB,EACxB,oBAAoB,EACpB,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,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,EACL,oBAAoB,EACpB,iBAAiB,EACjB,KAAK,iBAAiB,EACtB,KAAK,eAAe,GACrB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,6BAA6B,EAC7B,0BAA0B,EAC1B,KAAK,0BAA0B,EAC/B,KAAK,mBAAmB,GACzB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,0BAA0B,EAC1B,uBAAuB,EACvB,KAAK,wBAAwB,GAC9B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AACtF,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,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,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,EACL,uBAAuB,EACvB,YAAY,EACZ,oBAAoB,EACpB,kBAAkB,EAClB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,GAC1B,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,gBAAgB,EAChB,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,wBAAwB,EACxB,oBAAoB,EACpB,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export { HypequeryMCPServer, createMCPServer } from './server.js';
|
|
8
8
|
export { HypequeryMCPExecutor, createMCPExecutor, } from './executor.js';
|
|
9
|
+
export { HypequeryMCPDiscoveryExecutor, createMCPDiscoveryExecutor, } from './discovery-executor.js';
|
|
9
10
|
export { HypequeryMCPProtocolServer, createMCPProtocolServer, } from './protocol-server.js';
|
|
10
11
|
export { connectMCPServerStdio, startStdioMCPServer } from './stdio.js';
|
|
11
12
|
export { listDatasetsTool } from './tools/list-datasets.js';
|
|
@@ -5,5 +5,13 @@ import type { DatasetRegistry, MCPQueryLimits } from '../../types.js';
|
|
|
5
5
|
* type also accepts legacy metadata-only objects; retain a generic validator for
|
|
6
6
|
* those compatibility inputs until the publishing API replaces them.
|
|
7
7
|
*/
|
|
8
|
-
export declare function buildMCPQuerySchemas(datasets: DatasetRegistry, configured?: MCPQueryLimits
|
|
8
|
+
export declare function buildMCPQuerySchemas(datasets: DatasetRegistry, configured?: MCPQueryLimits,
|
|
9
|
+
/**
|
|
10
|
+
* Datasets offered as a `query_dataset` target. Defaults to all of them.
|
|
11
|
+
*
|
|
12
|
+
* A dataset outside this list keeps its metrics and its joins; it is only
|
|
13
|
+
* withheld as a direct target, which a hosted gateway needs when a caller is
|
|
14
|
+
* entitled to a metric on a dataset it may not query itself.
|
|
15
|
+
*/
|
|
16
|
+
queryableDatasets?: readonly string[]): CanonicalSemanticQuerySchemas;
|
|
9
17
|
//# sourceMappingURL=canonical-query-schemas.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"canonical-query-schemas.d.ts","sourceRoot":"","sources":["../../../src/tools/utils/canonical-query-schemas.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,6BAA6B,EAEnC,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AA0BtE;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,eAAe,EACzB,UAAU,CAAC,EAAE,cAAc,
|
|
1
|
+
{"version":3,"file":"canonical-query-schemas.d.ts","sourceRoot":"","sources":["../../../src/tools/utils/canonical-query-schemas.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,6BAA6B,EAEnC,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AA0BtE;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,eAAe,EACzB,UAAU,CAAC,EAAE,cAAc;AAC3B;;;;;;GAMG;AACH,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,GACpC,6BAA6B,CAqG/B"}
|
|
@@ -26,8 +26,17 @@ function withLegacyDirectMetrics(datasets) {
|
|
|
26
26
|
* type also accepts legacy metadata-only objects; retain a generic validator for
|
|
27
27
|
* those compatibility inputs until the publishing API replaces them.
|
|
28
28
|
*/
|
|
29
|
-
export function buildMCPQuerySchemas(datasets, configured
|
|
29
|
+
export function buildMCPQuerySchemas(datasets, configured,
|
|
30
|
+
/**
|
|
31
|
+
* Datasets offered as a `query_dataset` target. Defaults to all of them.
|
|
32
|
+
*
|
|
33
|
+
* A dataset outside this list keeps its metrics and its joins; it is only
|
|
34
|
+
* withheld as a direct target, which a hosted gateway needs when a caller is
|
|
35
|
+
* entitled to a metric on a dataset it may not query itself.
|
|
36
|
+
*/
|
|
37
|
+
queryableDatasets) {
|
|
30
38
|
const limits = resolveQueryLimits(undefined, configured);
|
|
39
|
+
const queryable = queryableDatasets === undefined ? undefined : new Set(queryableDatasets);
|
|
31
40
|
const entries = Object.entries(datasets).sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0));
|
|
32
41
|
if (entries.length === 0) {
|
|
33
42
|
const queryDatasetJsonSchema = toSemanticJsonSchema(queryDatasetArgsSchema);
|
|
@@ -45,7 +54,11 @@ export function buildMCPQuerySchemas(datasets, configured) {
|
|
|
45
54
|
});
|
|
46
55
|
}
|
|
47
56
|
if (entries.every(([, dataset]) => isCanonicalSchemaSource(dataset))) {
|
|
48
|
-
return buildCanonicalSemanticQuerySchemas(withLegacyDirectMetrics(datasets), {
|
|
57
|
+
return buildCanonicalSemanticQuerySchemas(withLegacyDirectMetrics(datasets), {
|
|
58
|
+
grainField: 'grain',
|
|
59
|
+
...limits,
|
|
60
|
+
...(queryableDatasets === undefined ? {} : { queryableDatasets }),
|
|
61
|
+
});
|
|
49
62
|
}
|
|
50
63
|
const datasetSchemas = [];
|
|
51
64
|
const metricSchemas = [];
|
|
@@ -54,9 +67,11 @@ export function buildMCPQuerySchemas(datasets, configured) {
|
|
|
54
67
|
for (const [name, dataset] of entries) {
|
|
55
68
|
if (isCanonicalSchemaSource(dataset)) {
|
|
56
69
|
const exact = buildCanonicalSemanticQuerySchemas(withLegacyDirectMetrics({ [name]: dataset }), { grainField: 'grain', ...limits });
|
|
57
|
-
|
|
70
|
+
if (queryable === undefined || queryable.has(name)) {
|
|
71
|
+
datasetSchemas.push(exact.queryDataset);
|
|
72
|
+
datasetJsonSchemas.push(exact.queryDatasetJsonSchema);
|
|
73
|
+
}
|
|
58
74
|
metricSchemas.push(exact.queryMetric);
|
|
59
|
-
datasetJsonSchemas.push(exact.queryDatasetJsonSchema);
|
|
60
75
|
metricJsonSchemas.push(exact.queryMetricJsonSchema);
|
|
61
76
|
}
|
|
62
77
|
else {
|
|
@@ -67,16 +82,18 @@ export function buildMCPQuerySchemas(datasets, configured) {
|
|
|
67
82
|
dataset: z.literal(name),
|
|
68
83
|
metric: z.string().min(1),
|
|
69
84
|
});
|
|
70
|
-
|
|
85
|
+
if (queryable === undefined || queryable.has(name)) {
|
|
86
|
+
datasetSchemas.push(queryDataset);
|
|
87
|
+
datasetJsonSchemas.push(advertiseDatasetQueryLimits(toSemanticJsonSchema(queryDataset), { [name]: dataset }, configured, true));
|
|
88
|
+
}
|
|
71
89
|
metricSchemas.push(queryMetric);
|
|
72
|
-
datasetJsonSchemas.push(advertiseDatasetQueryLimits(toSemanticJsonSchema(queryDataset), { [name]: dataset }, configured, true));
|
|
73
90
|
metricJsonSchemas.push(advertiseDatasetQueryLimits(toSemanticJsonSchema(queryMetric), { [name]: dataset }, configured, false));
|
|
74
91
|
}
|
|
75
92
|
}
|
|
76
|
-
const queryDataset = unionSchemas(datasetSchemas);
|
|
77
|
-
const queryMetric = unionSchemas(metricSchemas);
|
|
78
|
-
const queryDatasetJsonSchema = unionJsonSchemas(datasetJsonSchemas);
|
|
79
|
-
const queryMetricJsonSchema = unionJsonSchemas(metricJsonSchemas);
|
|
93
|
+
const queryDataset = unionSchemas(datasetSchemas, z.object({ dataset: z.never() }).strict());
|
|
94
|
+
const queryMetric = unionSchemas(metricSchemas, z.object({ dataset: z.never(), metric: z.never() }).strict());
|
|
95
|
+
const queryDatasetJsonSchema = unionJsonSchemas(datasetJsonSchemas, toSemanticJsonSchema(queryDataset));
|
|
96
|
+
const queryMetricJsonSchema = unionJsonSchemas(metricJsonSchemas, toSemanticJsonSchema(queryMetric));
|
|
80
97
|
const manifestHash = createHash('sha256').update(JSON.stringify({
|
|
81
98
|
query_dataset: queryDatasetJsonSchema,
|
|
82
99
|
query_metric: queryMetricJsonSchema,
|
|
@@ -96,12 +113,18 @@ function isCanonicalSchemaSource(dataset) {
|
|
|
96
113
|
return source.__type === 'dataset'
|
|
97
114
|
|| ('requiresTenant' in source && 'supportedGrains' in source && 'orderableFields' in source);
|
|
98
115
|
}
|
|
99
|
-
function unionSchemas(schemas) {
|
|
116
|
+
function unionSchemas(schemas, empty) {
|
|
117
|
+
// No variants means nothing is offered under this tool. `z.union([])` throws,
|
|
118
|
+
// and a permissive fallback would advertise every dataset instead of none.
|
|
119
|
+
if (schemas.length === 0)
|
|
120
|
+
return empty;
|
|
100
121
|
return schemas.length === 1
|
|
101
122
|
? schemas[0]
|
|
102
123
|
: z.union(schemas);
|
|
103
124
|
}
|
|
104
|
-
function unionJsonSchemas(schemas) {
|
|
125
|
+
function unionJsonSchemas(schemas, empty) {
|
|
126
|
+
if (schemas.length === 0)
|
|
127
|
+
return empty;
|
|
105
128
|
return schemas.length === 1
|
|
106
129
|
? schemas[0]
|
|
107
130
|
: { type: 'object', anyOf: schemas };
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const MCP_PACKAGE_VERSION = "0.
|
|
1
|
+
export declare const MCP_PACKAGE_VERSION = "0.7.0";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hypequery/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Governed ClickHouse MCP server for semantic metrics, datasets, Claude, Cursor, and AI agents",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mcp",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"dist"
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@hypequery/datasets": "^0.
|
|
36
|
+
"@hypequery/datasets": "^0.15.0",
|
|
37
37
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
38
38
|
"zod": "^3.23.8"
|
|
39
39
|
},
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"@types/node": "^20.11.30",
|
|
42
42
|
"typescript": "^5.7.3",
|
|
43
43
|
"vitest": "^3.2.6",
|
|
44
|
-
"@hypequery/clickhouse": "2.10.
|
|
44
|
+
"@hypequery/clickhouse": "2.10.1"
|
|
45
45
|
},
|
|
46
46
|
"repository": {
|
|
47
47
|
"type": "git",
|