mcp-server-db2i 2.0.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -0
- package/dist/config.d.ts +104 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +273 -5
- package/dist/config.js.map +1 -1
- package/dist/customTools/context.d.ts +27 -0
- package/dist/customTools/context.d.ts.map +1 -0
- package/dist/customTools/context.js +35 -0
- package/dist/customTools/context.js.map +1 -0
- package/dist/customTools/execute.d.ts +22 -0
- package/dist/customTools/execute.d.ts.map +1 -0
- package/dist/customTools/execute.js +134 -0
- package/dist/customTools/execute.js.map +1 -0
- package/dist/customTools/loader.d.ts +56 -0
- package/dist/customTools/loader.d.ts.map +1 -0
- package/dist/customTools/loader.js +213 -0
- package/dist/customTools/loader.js.map +1 -0
- package/dist/customTools/params.d.ts +23 -0
- package/dist/customTools/params.d.ts.map +1 -0
- package/dist/customTools/params.js +93 -0
- package/dist/customTools/params.js.map +1 -0
- package/dist/customTools/registry.d.ts +18 -0
- package/dist/customTools/registry.d.ts.map +1 -0
- package/dist/customTools/registry.js +23 -0
- package/dist/customTools/registry.js.map +1 -0
- package/dist/customTools/schema.d.ts +127 -0
- package/dist/customTools/schema.d.ts.map +1 -0
- package/dist/customTools/schema.js +193 -0
- package/dist/customTools/schema.js.map +1 -0
- package/dist/db/connection.d.ts +9 -0
- package/dist/db/connection.d.ts.map +1 -1
- package/dist/db/connection.js +91 -0
- package/dist/db/connection.js.map +1 -1
- package/dist/db/sqlServices.d.ts +65 -0
- package/dist/db/sqlServices.d.ts.map +1 -0
- package/dist/db/sqlServices.js +311 -0
- package/dist/db/sqlServices.js.map +1 -0
- package/dist/index.js +23 -1
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +260 -104
- package/dist/server.js.map +1 -1
- package/dist/tools/metadata.d.ts +24 -12
- package/dist/tools/metadata.d.ts.map +1 -1
- package/dist/tools/metadata.js +43 -8
- package/dist/tools/metadata.js.map +1 -1
- package/dist/tools/query.d.ts +5 -0
- package/dist/tools/query.d.ts.map +1 -1
- package/dist/tools/query.js +50 -2
- package/dist/tools/query.js.map +1 -1
- package/dist/tools/sqlLimit.d.ts +5 -0
- package/dist/tools/sqlLimit.d.ts.map +1 -1
- package/dist/tools/sqlLimit.js +12 -0
- package/dist/tools/sqlLimit.js.map +1 -1
- package/dist/tools/sqlServices.d.ts +51 -0
- package/dist/tools/sqlServices.d.ts.map +1 -0
- package/dist/tools/sqlServices.js +122 -0
- package/dist/tools/sqlServices.js.map +1 -0
- package/dist/transports/http.d.ts.map +1 -1
- package/dist/transports/http.js +40 -1
- package/dist/transports/http.js.map +1 -1
- package/dist/utils/formatResult.d.ts +22 -0
- package/dist/utils/formatResult.d.ts.map +1 -0
- package/dist/utils/formatResult.js +66 -0
- package/dist/utils/formatResult.js.map +1 -0
- package/dist/utils/security/schemaAllowlist.d.ts +27 -0
- package/dist/utils/security/schemaAllowlist.d.ts.map +1 -0
- package/dist/utils/security/schemaAllowlist.js +156 -0
- package/dist/utils/security/schemaAllowlist.js.map +1 -0
- package/dist/utils/security/sqlSecurityValidator.d.ts +0 -4
- package/dist/utils/security/sqlSecurityValidator.d.ts.map +1 -1
- package/dist/utils/security/sqlSecurityValidator.js +134 -38
- package/dist/utils/security/sqlSecurityValidator.js.map +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read business annotations loaded from YAML.
|
|
3
|
+
*/
|
|
4
|
+
import { getCustomTools } from './registry.js';
|
|
5
|
+
/**
|
|
6
|
+
* Annotation for SCHEMA.TABLE, if one was loaded.
|
|
7
|
+
*/
|
|
8
|
+
export function annotationFor(schema, table) {
|
|
9
|
+
const key = `${schema.trim().toUpperCase()}.${table.trim().toUpperCase()}`;
|
|
10
|
+
return getCustomTools().annotations.find((annotation) => annotation.table === key);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Annotations matching an entity name, a table, or both. Empty filters return every annotation.
|
|
14
|
+
*/
|
|
15
|
+
export function filterAnnotations(filter) {
|
|
16
|
+
const entity = filter.entity?.trim().toLowerCase();
|
|
17
|
+
const table = filter.table?.trim().toUpperCase();
|
|
18
|
+
return getCustomTools().annotations.filter((annotation) => {
|
|
19
|
+
if (entity && annotation.entity?.toLowerCase() !== entity) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
if (table) {
|
|
23
|
+
if (table.includes('.')) {
|
|
24
|
+
return annotation.table === table;
|
|
25
|
+
}
|
|
26
|
+
return annotation.table.endsWith(`.${table}`);
|
|
27
|
+
}
|
|
28
|
+
return true;
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
export function getBusinessContextTool(input) {
|
|
32
|
+
const data = filterAnnotations(input);
|
|
33
|
+
return { success: true, data, count: data.length };
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/customTools/context.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAW/C;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,MAAc,EAAE,KAAa;IACzD,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;IAC3E,OAAO,cAAc,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC;AACrF,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAA2C;IAC3E,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACnD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAEjD,OAAO,cAAc,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,EAAE;QACxD,IAAI,MAAM,IAAI,UAAU,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,MAAM,EAAE,CAAC;YAC1D,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,KAAK,EAAE,CAAC;YACV,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBACxB,OAAO,UAAU,CAAC,KAAK,KAAK,KAAK,CAAC;YACpC,CAAC;YACD,OAAO,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC;QAChD,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,KAA0C;IAC/E,MAAM,IAAI,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;IACtC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;AACrD,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run one business SQL tool on the read-only connection.
|
|
3
|
+
*/
|
|
4
|
+
import type { StoredTool } from './loader.js';
|
|
5
|
+
export interface CustomToolQueryResult {
|
|
6
|
+
success: boolean;
|
|
7
|
+
data?: unknown[];
|
|
8
|
+
rowCount?: number;
|
|
9
|
+
error?: string;
|
|
10
|
+
violations?: string[];
|
|
11
|
+
limitApplied?: number;
|
|
12
|
+
[key: string]: unknown;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Bind the tool's parameters and run its statement.
|
|
16
|
+
* The row cap is the tool's maxRows, or the default query limit, and never above QUERY_MAX_LIMIT.
|
|
17
|
+
*/
|
|
18
|
+
export declare function executeCustomTool(tool: StoredTool, args: Record<string, unknown>, options?: {
|
|
19
|
+
sessionId?: string;
|
|
20
|
+
defaultSchema?: string;
|
|
21
|
+
}): Promise<CustomToolQueryResult>;
|
|
22
|
+
//# sourceMappingURL=execute.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execute.d.ts","sourceRoot":"","sources":["../../src/customTools/execute.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAU9C,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAO,GAC3D,OAAO,CAAC,qBAAqB,CAAC,CAkDhC"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run one business SQL tool on the read-only connection.
|
|
3
|
+
*/
|
|
4
|
+
import { executeQuery } from '../db/connection.js';
|
|
5
|
+
import { isParseStatementMissing, parseStatement } from '../db/sqlServices.js';
|
|
6
|
+
import { applyQueryLimit, getAllowedSchemas, getQueryLimitConfig, isQueryParseCheckEnabled } from '../config.js';
|
|
7
|
+
import { applySqlRowLimit } from '../tools/sqlLimit.js';
|
|
8
|
+
import { createChildLogger } from '../utils/logger.js';
|
|
9
|
+
import { checkQuerySchemas } from '../utils/security/schemaAllowlist.js';
|
|
10
|
+
import { cacheParse, cachedParse } from './registry.js';
|
|
11
|
+
import { formatSchemaIssues, inputSchemaFor } from './schema.js';
|
|
12
|
+
const log = createChildLogger({ component: 'custom-tools' });
|
|
13
|
+
/**
|
|
14
|
+
* Bind the tool's parameters and run its statement.
|
|
15
|
+
* The row cap is the tool's maxRows, or the default query limit, and never above QUERY_MAX_LIMIT.
|
|
16
|
+
*/
|
|
17
|
+
export async function executeCustomTool(tool, args, options = {}) {
|
|
18
|
+
const filled = applyDefaults(tool.parameters, args);
|
|
19
|
+
const parsed = inputSchemaFor(tool.parameters).safeParse(filled);
|
|
20
|
+
if (!parsed.success) {
|
|
21
|
+
return { success: false, error: formatSchemaIssues(parsed.error) };
|
|
22
|
+
}
|
|
23
|
+
const values = tool.placeholderNames.map((name) => bindValue(parsed.data[name]));
|
|
24
|
+
const allowedSchemas = getAllowedSchemas();
|
|
25
|
+
if (allowedSchemas) {
|
|
26
|
+
const schemaResult = checkQuerySchemas(tool.sql, {
|
|
27
|
+
allowed: allowedSchemas,
|
|
28
|
+
defaultSchema: options.defaultSchema,
|
|
29
|
+
});
|
|
30
|
+
if (!schemaResult.ok) {
|
|
31
|
+
return {
|
|
32
|
+
success: false,
|
|
33
|
+
error: `Schema allowlist rejected the query: ${schemaResult.violations.join('; ')}`,
|
|
34
|
+
violations: schemaResult.violations,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const parsedOk = await ensureParsed(tool, options.sessionId);
|
|
39
|
+
if (!parsedOk.ok) {
|
|
40
|
+
return {
|
|
41
|
+
success: false,
|
|
42
|
+
error: parsedOk.error,
|
|
43
|
+
...(parsedOk.violations ? { violations: parsedOk.violations } : {}),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
const effectiveLimit = applyQueryLimit(tool.maxRows, getQueryLimitConfig());
|
|
47
|
+
const limitedSql = applySqlRowLimit(tool.sql, effectiveLimit);
|
|
48
|
+
try {
|
|
49
|
+
const result = await executeQuery(limitedSql, values, options.sessionId);
|
|
50
|
+
const rows = result.rows.slice(0, effectiveLimit);
|
|
51
|
+
log.info({ tool: tool.name, rowCount: rows.length, effectiveLimit }, 'Custom tool executed');
|
|
52
|
+
return {
|
|
53
|
+
success: true,
|
|
54
|
+
data: rows,
|
|
55
|
+
rowCount: rows.length,
|
|
56
|
+
limitApplied: effectiveLimit,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
const message = error instanceof Error ? error.message : 'Unknown error occurred';
|
|
61
|
+
log.debug({ err: error, tool: tool.name }, 'Custom tool failed');
|
|
62
|
+
return { success: false, error: message };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function applyDefaults(parameters, args) {
|
|
66
|
+
const filled = { ...args };
|
|
67
|
+
for (const [name, param] of Object.entries(parameters)) {
|
|
68
|
+
if (filled[name] === undefined && param.default !== undefined) {
|
|
69
|
+
filled[name] = param.default;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return filled;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Boolean values bind as 1 and 0. Omitted optional values bind as NULL.
|
|
76
|
+
*/
|
|
77
|
+
function bindValue(value) {
|
|
78
|
+
if (value === undefined || value === null) {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
if (value === true) {
|
|
82
|
+
return 1;
|
|
83
|
+
}
|
|
84
|
+
if (value === false) {
|
|
85
|
+
return 0;
|
|
86
|
+
}
|
|
87
|
+
return value;
|
|
88
|
+
}
|
|
89
|
+
async function ensureParsed(tool, sessionId) {
|
|
90
|
+
if (!isQueryParseCheckEnabled()) {
|
|
91
|
+
return { ok: true };
|
|
92
|
+
}
|
|
93
|
+
const cached = cachedParse(tool.name);
|
|
94
|
+
if (cached) {
|
|
95
|
+
return cached;
|
|
96
|
+
}
|
|
97
|
+
try {
|
|
98
|
+
const parsed = await parseStatement(tool.sql, sessionId);
|
|
99
|
+
const types = [
|
|
100
|
+
...new Set(parsed.map((row) => row.statementType).filter((type) => Boolean(type))),
|
|
101
|
+
];
|
|
102
|
+
let outcome;
|
|
103
|
+
if (parsed.length === 0 || types.length === 0 || types.some((type) => type !== 'QUERY')) {
|
|
104
|
+
const found = types.join(', ') || 'unknown';
|
|
105
|
+
outcome = {
|
|
106
|
+
ok: false,
|
|
107
|
+
error: parsed.length === 0
|
|
108
|
+
? 'The statement could not be parsed. Fix the SQL, or set QUERY_PARSE_CHECK=false to skip this check.'
|
|
109
|
+
: `PARSE_STATEMENT rejected the statement (type: ${found}). Only queries are allowed.`,
|
|
110
|
+
violations: parsed.length === 0
|
|
111
|
+
? ['The statement could not be parsed.']
|
|
112
|
+
: [`Statement type is ${found}.`],
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
outcome = { ok: true };
|
|
117
|
+
}
|
|
118
|
+
cacheParse(tool.name, outcome);
|
|
119
|
+
return outcome;
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
if (isParseStatementMissing(error)) {
|
|
123
|
+
const outcome = {
|
|
124
|
+
ok: false,
|
|
125
|
+
error: 'QSYS2.PARSE_STATEMENT is not available on this system. Set QUERY_PARSE_CHECK=false to run queries without this check.',
|
|
126
|
+
};
|
|
127
|
+
cacheParse(tool.name, outcome);
|
|
128
|
+
return outcome;
|
|
129
|
+
}
|
|
130
|
+
const message = error instanceof Error ? error.message : 'Unknown error occurred';
|
|
131
|
+
return { ok: false, error: message };
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=execute.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execute.js","sourceRoot":"","sources":["../../src/customTools/execute.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Load business SQL tools and annotations from YAML files.
|
|
3
|
+
*
|
|
4
|
+
* Statements are checked with the same read-only rules and schema allowlist
|
|
5
|
+
* as execute_query. A failing file stops startup.
|
|
6
|
+
*/
|
|
7
|
+
import { type ParameterDef, type RelationDef } from './schema.js';
|
|
8
|
+
export declare class CustomToolsError extends Error {
|
|
9
|
+
constructor(message: string);
|
|
10
|
+
}
|
|
11
|
+
export interface StoredRelation {
|
|
12
|
+
table: string;
|
|
13
|
+
join: Record<string, string>;
|
|
14
|
+
cardinality?: RelationDef['cardinality'];
|
|
15
|
+
description?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface StoredAnnotation {
|
|
18
|
+
table: string;
|
|
19
|
+
entity?: string;
|
|
20
|
+
description?: string;
|
|
21
|
+
columns: Record<string, string>;
|
|
22
|
+
relations: StoredRelation[];
|
|
23
|
+
}
|
|
24
|
+
export interface StoredTool {
|
|
25
|
+
name: string;
|
|
26
|
+
title: string;
|
|
27
|
+
toolset?: string;
|
|
28
|
+
description: string;
|
|
29
|
+
parameters: Record<string, ParameterDef>;
|
|
30
|
+
maxRows?: number;
|
|
31
|
+
/** SQL with :name placeholders already rewritten to ? markers. */
|
|
32
|
+
sql: string;
|
|
33
|
+
/** Placeholder names in bind order. */
|
|
34
|
+
placeholderNames: string[];
|
|
35
|
+
source: string;
|
|
36
|
+
}
|
|
37
|
+
export interface LoadedCustomTools {
|
|
38
|
+
tools: StoredTool[];
|
|
39
|
+
annotations: StoredAnnotation[];
|
|
40
|
+
}
|
|
41
|
+
export interface LoadCustomToolsOptions {
|
|
42
|
+
/** Uppercased library names. Omit to skip the schema allowlist. */
|
|
43
|
+
allowedSchemas?: string[];
|
|
44
|
+
/** Schema unqualified names resolve to while the allowlist is on. */
|
|
45
|
+
defaultSchema?: string;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Load the files or directories listed in MCP_CUSTOM_TOOLS.
|
|
49
|
+
* An unset or blank value loads nothing.
|
|
50
|
+
*/
|
|
51
|
+
export declare function loadCustomToolsFromEnv(): LoadedCustomTools;
|
|
52
|
+
/**
|
|
53
|
+
* Read YAML files and check every statement before the server accepts connections.
|
|
54
|
+
*/
|
|
55
|
+
export declare function loadCustomTools(inputs: readonly string[], options?: LoadCustomToolsOptions): LoadedCustomTools;
|
|
56
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/customTools/loader.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,WAAW,EAEjB,MAAM,aAAa,CAAC;AAErB,qBAAa,gBAAiB,SAAQ,KAAK;gBAC7B,OAAO,EAAE,MAAM;CAI5B;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,WAAW,CAAC,EAAE,WAAW,CAAC,aAAa,CAAC,CAAC;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,SAAS,EAAE,cAAc,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kEAAkE;IAClE,GAAG,EAAE,MAAM,CAAC;IACZ,uCAAuC;IACvC,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,WAAW,EAAE,gBAAgB,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,sBAAsB;IACrC,mEAAmE;IACnE,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,qEAAqE;IACrE,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAID;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,iBAAiB,CAW1D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,SAAS,MAAM,EAAE,EACzB,OAAO,GAAE,sBAA2B,GACnC,iBAAiB,CAwCnB"}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Load business SQL tools and annotations from YAML files.
|
|
3
|
+
*
|
|
4
|
+
* Statements are checked with the same read-only rules and schema allowlist
|
|
5
|
+
* as execute_query. A failing file stops startup.
|
|
6
|
+
*/
|
|
7
|
+
import { readdirSync, readFileSync, statSync } from 'node:fs';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import { parseDocument } from 'yaml';
|
|
10
|
+
import { getAllowedSchemas, TOOL_NAMES } from '../config.js';
|
|
11
|
+
import { checkQuerySchemas } from '../utils/security/schemaAllowlist.js';
|
|
12
|
+
import { validateQuery } from '../utils/security/sqlSecurityValidator.js';
|
|
13
|
+
import { PlaceholderError, rewriteNamedPlaceholders } from './params.js';
|
|
14
|
+
import { customToolsFileSchema, formatSchemaIssues, } from './schema.js';
|
|
15
|
+
export class CustomToolsError extends Error {
|
|
16
|
+
constructor(message) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.name = 'CustomToolsError';
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
const EMPTY = { tools: [], annotations: [] };
|
|
22
|
+
/**
|
|
23
|
+
* Load the files or directories listed in MCP_CUSTOM_TOOLS.
|
|
24
|
+
* An unset or blank value loads nothing.
|
|
25
|
+
*/
|
|
26
|
+
export function loadCustomToolsFromEnv() {
|
|
27
|
+
const raw = process.env.MCP_CUSTOM_TOOLS;
|
|
28
|
+
if (raw === undefined || raw.trim() === '') {
|
|
29
|
+
return EMPTY;
|
|
30
|
+
}
|
|
31
|
+
const paths = raw.split(',').map((entry) => entry.trim()).filter((entry) => entry.length > 0);
|
|
32
|
+
return loadCustomTools(paths, {
|
|
33
|
+
allowedSchemas: getAllowedSchemas(),
|
|
34
|
+
defaultSchema: process.env.DB2I_SCHEMA,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Read YAML files and check every statement before the server accepts connections.
|
|
39
|
+
*/
|
|
40
|
+
export function loadCustomTools(inputs, options = {}) {
|
|
41
|
+
const files = inputs.flatMap((input) => collectFiles(input));
|
|
42
|
+
const tools = [];
|
|
43
|
+
const annotations = [];
|
|
44
|
+
const toolSources = new Map();
|
|
45
|
+
const annotationSources = new Map();
|
|
46
|
+
for (const file of files) {
|
|
47
|
+
const parsed = readFile(file);
|
|
48
|
+
for (const tool of parsed.tools ?? []) {
|
|
49
|
+
const stored = checkTool(tool, file, options);
|
|
50
|
+
const previous = toolSources.get(stored.name);
|
|
51
|
+
if (previous) {
|
|
52
|
+
throw new CustomToolsError(`Tool ${stored.name} is defined in both ${previous} and ${displayPath(file)}.`);
|
|
53
|
+
}
|
|
54
|
+
if (TOOL_NAMES.includes(stored.name)) {
|
|
55
|
+
throw new CustomToolsError(`${displayPath(file)}: tool ${stored.name} is already a built-in tool.`);
|
|
56
|
+
}
|
|
57
|
+
toolSources.set(stored.name, displayPath(file));
|
|
58
|
+
tools.push(stored);
|
|
59
|
+
}
|
|
60
|
+
for (const [table, annotation] of Object.entries(parsed.annotations ?? {})) {
|
|
61
|
+
const stored = storeAnnotation(table, annotation);
|
|
62
|
+
const previous = annotationSources.get(stored.table);
|
|
63
|
+
if (previous) {
|
|
64
|
+
throw new CustomToolsError(`Annotation ${stored.table} is defined in both ${previous} and ${displayPath(file)}.`);
|
|
65
|
+
}
|
|
66
|
+
annotationSources.set(stored.table, displayPath(file));
|
|
67
|
+
annotations.push(stored);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return { tools, annotations };
|
|
71
|
+
}
|
|
72
|
+
function readFile(file) {
|
|
73
|
+
let text;
|
|
74
|
+
try {
|
|
75
|
+
text = readFileSync(file, 'utf8');
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
const message = error instanceof Error ? error.message : 'Could not read file';
|
|
79
|
+
throw new CustomToolsError(`${displayPath(file)}: ${message}`);
|
|
80
|
+
}
|
|
81
|
+
const doc = parseDocument(text, { schema: 'core' });
|
|
82
|
+
if (doc.errors.length > 0) {
|
|
83
|
+
throw new CustomToolsError(`${displayPath(file)}: ${doc.errors.map((error) => error.message).join('; ')}`);
|
|
84
|
+
}
|
|
85
|
+
const parsed = customToolsFileSchema.safeParse(doc.toJS());
|
|
86
|
+
if (!parsed.success) {
|
|
87
|
+
throw new CustomToolsError(`${displayPath(file)}: ${formatSchemaIssues(parsed.error)}`);
|
|
88
|
+
}
|
|
89
|
+
return parsed.data;
|
|
90
|
+
}
|
|
91
|
+
function checkTool(tool, file, options) {
|
|
92
|
+
const where = `${displayPath(file)}: tool ${tool.name}`;
|
|
93
|
+
const parameters = tool.parameters ?? {};
|
|
94
|
+
let rewritten;
|
|
95
|
+
try {
|
|
96
|
+
rewritten = rewriteNamedPlaceholders(tool.sql);
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
if (error instanceof PlaceholderError) {
|
|
100
|
+
throw new CustomToolsError(`${where}: ${error.message}`);
|
|
101
|
+
}
|
|
102
|
+
throw error;
|
|
103
|
+
}
|
|
104
|
+
const declared = new Set(Object.keys(parameters));
|
|
105
|
+
const used = new Set(rewritten.names);
|
|
106
|
+
for (const name of used) {
|
|
107
|
+
if (!declared.has(name)) {
|
|
108
|
+
throw new CustomToolsError(`${where}: placeholder :${name} has no parameter definition.`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
for (const name of declared) {
|
|
112
|
+
if (!used.has(name)) {
|
|
113
|
+
throw new CustomToolsError(`${where}: parameter ${name} is not used in the SQL.`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const security = validateQuery(rewritten.sql);
|
|
117
|
+
if (!security.isValid) {
|
|
118
|
+
throw new CustomToolsError(`${where}: Security validation failed: ${security.violations.join('; ')}`);
|
|
119
|
+
}
|
|
120
|
+
if (options.allowedSchemas && options.allowedSchemas.length > 0) {
|
|
121
|
+
const schemaResult = checkQuerySchemas(rewritten.sql, {
|
|
122
|
+
allowed: options.allowedSchemas,
|
|
123
|
+
defaultSchema: options.defaultSchema,
|
|
124
|
+
});
|
|
125
|
+
if (!schemaResult.ok) {
|
|
126
|
+
throw new CustomToolsError(`${where}: Schema allowlist rejected the query: ${schemaResult.violations.join('; ')}`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
name: tool.name,
|
|
131
|
+
title: tool.title,
|
|
132
|
+
...(tool.toolset ? { toolset: tool.toolset } : {}),
|
|
133
|
+
description: tool.description,
|
|
134
|
+
parameters,
|
|
135
|
+
...(tool.maxRows !== undefined ? { maxRows: tool.maxRows } : {}),
|
|
136
|
+
sql: rewritten.sql,
|
|
137
|
+
placeholderNames: rewritten.names,
|
|
138
|
+
source: displayPath(file),
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
function storeAnnotation(table, annotation) {
|
|
142
|
+
const columns = {};
|
|
143
|
+
for (const [column, text] of Object.entries(annotation.columns ?? {})) {
|
|
144
|
+
columns[column.toUpperCase()] = text;
|
|
145
|
+
}
|
|
146
|
+
const relations = (annotation.relations ?? []).map((relation) => {
|
|
147
|
+
const join = {};
|
|
148
|
+
for (const [from, to] of Object.entries(relation.join)) {
|
|
149
|
+
join[from.toUpperCase()] = to.toUpperCase();
|
|
150
|
+
}
|
|
151
|
+
return {
|
|
152
|
+
table: relation.table.toUpperCase(),
|
|
153
|
+
join,
|
|
154
|
+
...(relation.cardinality ? { cardinality: relation.cardinality } : {}),
|
|
155
|
+
...(relation.description ? { description: relation.description } : {}),
|
|
156
|
+
};
|
|
157
|
+
});
|
|
158
|
+
return {
|
|
159
|
+
table: table.toUpperCase(),
|
|
160
|
+
...(annotation.entity ? { entity: annotation.entity } : {}),
|
|
161
|
+
...(annotation.description ? { description: annotation.description } : {}),
|
|
162
|
+
columns,
|
|
163
|
+
relations,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
function collectFiles(input) {
|
|
167
|
+
const resolved = path.resolve(input);
|
|
168
|
+
let info;
|
|
169
|
+
try {
|
|
170
|
+
info = statSync(resolved);
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
throw new CustomToolsError(`Custom tools path not found: ${input}`);
|
|
174
|
+
}
|
|
175
|
+
if (info.isFile()) {
|
|
176
|
+
if (!isYaml(resolved)) {
|
|
177
|
+
throw new CustomToolsError(`Custom tools file must be .yaml or .yml: ${input}`);
|
|
178
|
+
}
|
|
179
|
+
return [resolved];
|
|
180
|
+
}
|
|
181
|
+
if (!info.isDirectory()) {
|
|
182
|
+
throw new CustomToolsError(`Custom tools path is not a file or directory: ${input}`);
|
|
183
|
+
}
|
|
184
|
+
const found = [];
|
|
185
|
+
walk(resolved, found);
|
|
186
|
+
found.sort((a, b) => a.localeCompare(b));
|
|
187
|
+
if (found.length === 0) {
|
|
188
|
+
throw new CustomToolsError(`No YAML files found in ${input}`);
|
|
189
|
+
}
|
|
190
|
+
return found;
|
|
191
|
+
}
|
|
192
|
+
function walk(dir, found) {
|
|
193
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
194
|
+
if (entry.name.startsWith('.')) {
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
const full = path.join(dir, entry.name);
|
|
198
|
+
if (entry.isDirectory()) {
|
|
199
|
+
walk(full, found);
|
|
200
|
+
}
|
|
201
|
+
else if (entry.isFile() && isYaml(entry.name)) {
|
|
202
|
+
found.push(full);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
function isYaml(file) {
|
|
207
|
+
return file.toLowerCase().endsWith('.yaml') || file.toLowerCase().endsWith('.yml');
|
|
208
|
+
}
|
|
209
|
+
function displayPath(file) {
|
|
210
|
+
const relative = path.relative(process.cwd(), file);
|
|
211
|
+
return relative.startsWith('..') ? file : relative;
|
|
212
|
+
}
|
|
213
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/customTools/loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turn :name placeholders into positional ? markers.
|
|
3
|
+
*
|
|
4
|
+
* Names inside string literals, quoted identifiers, and comments stay as text.
|
|
5
|
+
* A bare ? is rejected so bind order cannot be mixed with hand-written markers.
|
|
6
|
+
*/
|
|
7
|
+
export declare class PlaceholderError extends Error {
|
|
8
|
+
constructor(message: string);
|
|
9
|
+
}
|
|
10
|
+
export interface RewrittenSql {
|
|
11
|
+
/** SQL with :name placeholders replaced by ? markers. */
|
|
12
|
+
sql: string;
|
|
13
|
+
/** Placeholder names in bind order. Repeated names are kept. */
|
|
14
|
+
names: string[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Replace :name placeholders with ? and return the names in bind order.
|
|
18
|
+
*
|
|
19
|
+
* @throws PlaceholderError when a colon is not a :name placeholder, a ? marker
|
|
20
|
+
* is already present, or a quote or block comment is left open.
|
|
21
|
+
*/
|
|
22
|
+
export declare function rewriteNamedPlaceholders(sql: string): RewrittenSql;
|
|
23
|
+
//# sourceMappingURL=params.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"params.d.ts","sourceRoot":"","sources":["../../src/customTools/params.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,qBAAa,gBAAiB,SAAQ,KAAK;gBAC7B,OAAO,EAAE,MAAM;CAI5B;AAED,MAAM,WAAW,YAAY;IAC3B,yDAAyD;IACzD,GAAG,EAAE,MAAM,CAAC;IACZ,gEAAgE;IAChE,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,CAwDlE"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turn :name placeholders into positional ? markers.
|
|
3
|
+
*
|
|
4
|
+
* Names inside string literals, quoted identifiers, and comments stay as text.
|
|
5
|
+
* A bare ? is rejected so bind order cannot be mixed with hand-written markers.
|
|
6
|
+
*/
|
|
7
|
+
const PLACEHOLDER_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
8
|
+
export class PlaceholderError extends Error {
|
|
9
|
+
constructor(message) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = 'PlaceholderError';
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Replace :name placeholders with ? and return the names in bind order.
|
|
16
|
+
*
|
|
17
|
+
* @throws PlaceholderError when a colon is not a :name placeholder, a ? marker
|
|
18
|
+
* is already present, or a quote or block comment is left open.
|
|
19
|
+
*/
|
|
20
|
+
export function rewriteNamedPlaceholders(sql) {
|
|
21
|
+
let out = '';
|
|
22
|
+
const names = [];
|
|
23
|
+
let i = 0;
|
|
24
|
+
while (i < sql.length) {
|
|
25
|
+
const ch = sql[i];
|
|
26
|
+
const next = sql[i + 1];
|
|
27
|
+
if (ch === '-' && next === '-') {
|
|
28
|
+
const end = sql.indexOf('\n', i);
|
|
29
|
+
if (end === -1) {
|
|
30
|
+
out += sql.slice(i);
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
out += sql.slice(i, end);
|
|
34
|
+
i = end;
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (ch === '/' && next === '*') {
|
|
38
|
+
const end = sql.indexOf('*/', i + 2);
|
|
39
|
+
if (end === -1) {
|
|
40
|
+
throw new PlaceholderError('Unclosed block comment.');
|
|
41
|
+
}
|
|
42
|
+
out += sql.slice(i, end + 2);
|
|
43
|
+
i = end + 2;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (ch === "'" || ch === '"') {
|
|
47
|
+
const end = endOfQuoted(sql, i, ch);
|
|
48
|
+
out += sql.slice(i, end);
|
|
49
|
+
i = end;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (ch === '?') {
|
|
53
|
+
throw new PlaceholderError('Use :name placeholders. Question marks are reserved for bound parameters.');
|
|
54
|
+
}
|
|
55
|
+
if (ch === ':') {
|
|
56
|
+
const name = readPlaceholderName(sql, i + 1);
|
|
57
|
+
names.push(name);
|
|
58
|
+
out += '?';
|
|
59
|
+
i += 1 + name.length;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
out += ch;
|
|
63
|
+
i += 1;
|
|
64
|
+
}
|
|
65
|
+
return { sql: out, names };
|
|
66
|
+
}
|
|
67
|
+
function readPlaceholderName(sql, start) {
|
|
68
|
+
let end = start;
|
|
69
|
+
while (end < sql.length && /[A-Za-z0-9_]/.test(sql[end])) {
|
|
70
|
+
end += 1;
|
|
71
|
+
}
|
|
72
|
+
const name = sql.slice(start, end);
|
|
73
|
+
if (!PLACEHOLDER_NAME.test(name)) {
|
|
74
|
+
throw new PlaceholderError('Invalid placeholder. Write :name using letters, digits, and underscores.');
|
|
75
|
+
}
|
|
76
|
+
return name;
|
|
77
|
+
}
|
|
78
|
+
function endOfQuoted(sql, start, quote) {
|
|
79
|
+
let i = start + 1;
|
|
80
|
+
while (i < sql.length) {
|
|
81
|
+
if (sql[i] === quote) {
|
|
82
|
+
if (sql[i + 1] === quote) {
|
|
83
|
+
i += 2;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
return i + 1;
|
|
87
|
+
}
|
|
88
|
+
i += 1;
|
|
89
|
+
}
|
|
90
|
+
const kind = quote === "'" ? 'string literal' : 'quoted identifier';
|
|
91
|
+
throw new PlaceholderError(`Unclosed ${kind}.`);
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=params.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"params.js","sourceRoot":"","sources":["../../src/customTools/params.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Process-wide custom tools, loaded once at startup.
|
|
3
|
+
*/
|
|
4
|
+
import type { LoadedCustomTools, StoredAnnotation, StoredTool } from './loader.js';
|
|
5
|
+
type ParseOutcome = {
|
|
6
|
+
ok: true;
|
|
7
|
+
} | {
|
|
8
|
+
ok: false;
|
|
9
|
+
error: string;
|
|
10
|
+
violations?: string[];
|
|
11
|
+
};
|
|
12
|
+
export declare function cachedParse(toolName: string): ParseOutcome | undefined;
|
|
13
|
+
export declare function cacheParse(toolName: string, outcome: ParseOutcome): void;
|
|
14
|
+
export declare function setCustomTools(loaded: LoadedCustomTools): void;
|
|
15
|
+
export declare function getCustomTools(): LoadedCustomTools;
|
|
16
|
+
export declare function resetCustomTools(): void;
|
|
17
|
+
export type { StoredAnnotation, StoredTool };
|
|
18
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/customTools/registry.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAMnF,KAAK,YAAY,GACb;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GACZ;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAIxD,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAEtE;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI,CAExE;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAG9D;AAED,wBAAgB,cAAc,IAAI,iBAAiB,CAElD;AAED,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC;AAED,YAAY,EAAE,gBAAgB,EAAE,UAAU,EAAE,CAAC"}
|