mcp-server-db2i 1.0.0 → 1.1.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 +45 -3
- package/dist/config.d.ts +29 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +25 -0
- package/dist/config.js.map +1 -1
- package/dist/db/connection.d.ts +0 -13
- package/dist/db/connection.d.ts.map +1 -1
- package/dist/db/connection.js +15 -32
- package/dist/db/connection.js.map +1 -1
- package/dist/db/queries.d.ts +22 -0
- package/dist/db/queries.d.ts.map +1 -1
- package/dist/db/queries.js +42 -35
- package/dist/db/queries.js.map +1 -1
- package/dist/index.js +43 -136
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +39 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +133 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/metadata.d.ts +51 -194
- package/dist/tools/metadata.d.ts.map +1 -1
- package/dist/tools/metadata.js +35 -167
- package/dist/tools/metadata.js.map +1 -1
- package/dist/tools/query.d.ts +7 -21
- package/dist/tools/query.d.ts.map +1 -1
- package/dist/tools/query.js +12 -22
- package/dist/tools/query.js.map +1 -1
- package/dist/utils/logger.d.ts +48 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +124 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/rateLimiter.d.ts +90 -0
- package/dist/utils/rateLimiter.d.ts.map +1 -0
- package/dist/utils/rateLimiter.js +215 -0
- package/dist/utils/rateLimiter.js.map +1 -0
- package/dist/utils/security/sqlSecurityValidator.d.ts +101 -0
- package/dist/utils/security/sqlSecurityValidator.d.ts.map +1 -0
- package/dist/utils/security/sqlSecurityValidator.js +312 -0
- package/dist/utils/security/sqlSecurityValidator.js.map +1 -0
- package/package.json +17 -3
package/dist/index.js
CHANGED
|
@@ -5,170 +5,77 @@
|
|
|
5
5
|
* A Model Context Protocol server for querying and inspecting
|
|
6
6
|
* IBM DB2 for i (DB2i) databases using the JT400 JDBC driver.
|
|
7
7
|
*/
|
|
8
|
-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
9
8
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
10
|
-
import { z } from 'zod';
|
|
11
9
|
import { loadConfig } from './config.js';
|
|
12
10
|
import { initializePool, testConnection } from './db/connection.js';
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
const SERVER_VERSION = '1.0.0';
|
|
17
|
-
/**
|
|
18
|
-
* Create and configure the MCP server
|
|
19
|
-
*/
|
|
20
|
-
function createServer() {
|
|
21
|
-
const server = new McpServer({
|
|
22
|
-
name: SERVER_NAME,
|
|
23
|
-
version: SERVER_VERSION,
|
|
24
|
-
});
|
|
25
|
-
// Register execute_query tool
|
|
26
|
-
server.tool('execute_query', 'Execute a read-only SQL SELECT query against the IBM DB2i database. Only SELECT statements are allowed for security. Results are limited by default to prevent large result sets.', {
|
|
27
|
-
sql: z.string().describe('SQL SELECT query to execute'),
|
|
28
|
-
params: z.array(z.unknown()).optional().describe('Query parameters for prepared statement'),
|
|
29
|
-
limit: z.number().optional().default(1000).describe('Maximum number of rows to return (default: 1000)'),
|
|
30
|
-
}, async (args) => {
|
|
31
|
-
const result = await executeQueryTool({
|
|
32
|
-
sql: args.sql,
|
|
33
|
-
params: args.params,
|
|
34
|
-
limit: args.limit ?? 1000,
|
|
35
|
-
});
|
|
36
|
-
return {
|
|
37
|
-
content: [
|
|
38
|
-
{
|
|
39
|
-
type: 'text',
|
|
40
|
-
text: JSON.stringify(result, null, 2),
|
|
41
|
-
},
|
|
42
|
-
],
|
|
43
|
-
};
|
|
44
|
-
});
|
|
45
|
-
// Register list_schemas tool
|
|
46
|
-
server.tool('list_schemas', 'List all schemas (libraries) in the IBM DB2i database. Optionally filter by name pattern using * as wildcard.', {
|
|
47
|
-
filter: z.string().optional().describe('Filter pattern for schema names. Use * as wildcard. Example: "QSYS*" matches schemas starting with QSYS'),
|
|
48
|
-
}, async (args) => {
|
|
49
|
-
const result = await listSchemasTool({ filter: args.filter });
|
|
50
|
-
return {
|
|
51
|
-
content: [
|
|
52
|
-
{
|
|
53
|
-
type: 'text',
|
|
54
|
-
text: JSON.stringify(result, null, 2),
|
|
55
|
-
},
|
|
56
|
-
],
|
|
57
|
-
};
|
|
58
|
-
});
|
|
59
|
-
// Register list_tables tool
|
|
60
|
-
server.tool('list_tables', 'List all tables in a schema (library). Uses DB2I_SCHEMA env var if schema not provided. Optionally filter by name pattern using * as wildcard.', {
|
|
61
|
-
schema: z.string().optional().describe('Schema (library) name to list tables from. Uses DB2I_SCHEMA env var if not provided.'),
|
|
62
|
-
filter: z.string().optional().describe('Filter pattern for table names. Use * as wildcard. Example: "CUST*" matches tables starting with CUST'),
|
|
63
|
-
}, async (args) => {
|
|
64
|
-
const result = await listTablesTool({ schema: args.schema, filter: args.filter });
|
|
65
|
-
return {
|
|
66
|
-
content: [
|
|
67
|
-
{
|
|
68
|
-
type: 'text',
|
|
69
|
-
text: JSON.stringify(result, null, 2),
|
|
70
|
-
},
|
|
71
|
-
],
|
|
72
|
-
};
|
|
73
|
-
});
|
|
74
|
-
// Register describe_table tool
|
|
75
|
-
server.tool('describe_table', 'Get detailed column information for a specific table including data types, lengths, nullability, defaults, and CCSID. Uses DB2I_SCHEMA env var if schema not provided.', {
|
|
76
|
-
schema: z.string().optional().describe('Schema (library) name containing the table. Uses DB2I_SCHEMA env var if not provided.'),
|
|
77
|
-
table: z.string().describe('Table name to describe'),
|
|
78
|
-
}, async (args) => {
|
|
79
|
-
const result = await describeTableTool({ schema: args.schema, table: args.table });
|
|
80
|
-
return {
|
|
81
|
-
content: [
|
|
82
|
-
{
|
|
83
|
-
type: 'text',
|
|
84
|
-
text: JSON.stringify(result, null, 2),
|
|
85
|
-
},
|
|
86
|
-
],
|
|
87
|
-
};
|
|
88
|
-
});
|
|
89
|
-
// Register list_views tool
|
|
90
|
-
server.tool('list_views', 'List all views in a schema (library). Uses DB2I_SCHEMA env var if schema not provided. Optionally filter by name pattern using * as wildcard.', {
|
|
91
|
-
schema: z.string().optional().describe('Schema (library) name to list views from. Uses DB2I_SCHEMA env var if not provided.'),
|
|
92
|
-
filter: z.string().optional().describe('Filter pattern for view names. Use * as wildcard.'),
|
|
93
|
-
}, async (args) => {
|
|
94
|
-
const result = await listViewsTool({ schema: args.schema, filter: args.filter });
|
|
95
|
-
return {
|
|
96
|
-
content: [
|
|
97
|
-
{
|
|
98
|
-
type: 'text',
|
|
99
|
-
text: JSON.stringify(result, null, 2),
|
|
100
|
-
},
|
|
101
|
-
],
|
|
102
|
-
};
|
|
103
|
-
});
|
|
104
|
-
// Register list_indexes tool
|
|
105
|
-
server.tool('list_indexes', 'List all indexes for a specific table including uniqueness and column information. Uses DB2I_SCHEMA env var if schema not provided.', {
|
|
106
|
-
schema: z.string().optional().describe('Schema (library) name containing the table. Uses DB2I_SCHEMA env var if not provided.'),
|
|
107
|
-
table: z.string().describe('Table name to list indexes for'),
|
|
108
|
-
}, async (args) => {
|
|
109
|
-
const result = await listIndexesTool({ schema: args.schema, table: args.table });
|
|
110
|
-
return {
|
|
111
|
-
content: [
|
|
112
|
-
{
|
|
113
|
-
type: 'text',
|
|
114
|
-
text: JSON.stringify(result, null, 2),
|
|
115
|
-
},
|
|
116
|
-
],
|
|
117
|
-
};
|
|
118
|
-
});
|
|
119
|
-
// Register get_table_constraints tool
|
|
120
|
-
server.tool('get_table_constraints', 'Get all constraints (primary keys, foreign keys, unique constraints) for a specific table. Uses DB2I_SCHEMA env var if schema not provided.', {
|
|
121
|
-
schema: z.string().optional().describe('Schema (library) name containing the table. Uses DB2I_SCHEMA env var if not provided.'),
|
|
122
|
-
table: z.string().describe('Table name to get constraints for'),
|
|
123
|
-
}, async (args) => {
|
|
124
|
-
const result = await getTableConstraintsTool({ schema: args.schema, table: args.table });
|
|
125
|
-
return {
|
|
126
|
-
content: [
|
|
127
|
-
{
|
|
128
|
-
type: 'text',
|
|
129
|
-
text: JSON.stringify(result, null, 2),
|
|
130
|
-
},
|
|
131
|
-
],
|
|
132
|
-
};
|
|
133
|
-
});
|
|
134
|
-
return server;
|
|
135
|
-
}
|
|
11
|
+
import { logger, flushLogger } from './utils/logger.js';
|
|
12
|
+
import { getRateLimiter } from './utils/rateLimiter.js';
|
|
13
|
+
import { createServer, SERVER_NAME, SERVER_VERSION } from './server.js';
|
|
136
14
|
/**
|
|
137
15
|
* Main entry point
|
|
138
16
|
*/
|
|
139
17
|
async function main() {
|
|
18
|
+
let server = null;
|
|
19
|
+
/**
|
|
20
|
+
* Gracefully shutdown the server
|
|
21
|
+
*/
|
|
22
|
+
function shutdown(signal) {
|
|
23
|
+
logger.info(`Received ${signal}, shutting down...`);
|
|
24
|
+
if (server) {
|
|
25
|
+
server.close().then(() => {
|
|
26
|
+
logger.info('MCP server closed');
|
|
27
|
+
flushLogger();
|
|
28
|
+
process.exit(0);
|
|
29
|
+
}).catch((error) => {
|
|
30
|
+
logger.error({ err: error }, 'Error closing MCP server');
|
|
31
|
+
flushLogger();
|
|
32
|
+
process.exit(1);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
flushLogger();
|
|
37
|
+
process.exit(0);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
140
40
|
try {
|
|
41
|
+
logger.info('Starting MCP server...');
|
|
141
42
|
// Load configuration from environment variables
|
|
142
43
|
const config = loadConfig();
|
|
44
|
+
logger.debug({ hostname: config.hostname, port: config.port }, 'Configuration loaded');
|
|
143
45
|
// Initialize database connection pool
|
|
144
46
|
initializePool(config);
|
|
47
|
+
logger.debug('Database connection pool initialized');
|
|
145
48
|
// Test the connection
|
|
146
49
|
const connected = await testConnection();
|
|
147
50
|
if (!connected) {
|
|
148
|
-
|
|
51
|
+
logger.warn('Could not verify database connection. The server will start but queries may fail.');
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
logger.info('Database connection verified');
|
|
149
55
|
}
|
|
56
|
+
// Initialize rate limiter (logs its own config)
|
|
57
|
+
getRateLimiter();
|
|
150
58
|
// Create MCP server
|
|
151
|
-
|
|
59
|
+
server = createServer();
|
|
60
|
+
logger.debug('MCP server instance created');
|
|
152
61
|
// Connect via stdio transport
|
|
153
62
|
const transport = new StdioServerTransport();
|
|
154
63
|
await server.connect(transport);
|
|
64
|
+
logger.info({ name: SERVER_NAME, version: SERVER_VERSION }, 'MCP server connected via stdio transport');
|
|
155
65
|
// Handle shutdown gracefully
|
|
156
|
-
process.on('SIGINT', () =>
|
|
157
|
-
|
|
158
|
-
});
|
|
159
|
-
process.on('SIGTERM', () => {
|
|
160
|
-
process.exit(0);
|
|
161
|
-
});
|
|
66
|
+
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
67
|
+
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
162
68
|
}
|
|
163
69
|
catch (error) {
|
|
164
|
-
|
|
165
|
-
|
|
70
|
+
logger.fatal({ err: error }, 'Failed to start MCP server');
|
|
71
|
+
flushLogger();
|
|
166
72
|
process.exit(1);
|
|
167
73
|
}
|
|
168
74
|
}
|
|
169
75
|
// Run the server
|
|
170
76
|
main().catch((error) => {
|
|
171
|
-
|
|
77
|
+
logger.fatal({ err: error }, 'Fatal error during server startup');
|
|
78
|
+
flushLogger();
|
|
172
79
|
process.exit(1);
|
|
173
80
|
});
|
|
174
81
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AAEH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Server Factory
|
|
3
|
+
*
|
|
4
|
+
* Creates and configures the MCP server with all tools registered.
|
|
5
|
+
* Extracted from index.ts for testability.
|
|
6
|
+
*/
|
|
7
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
8
|
+
export declare const SERVER_NAME: string;
|
|
9
|
+
export declare const SERVER_VERSION: string;
|
|
10
|
+
/**
|
|
11
|
+
* Standard tool result type
|
|
12
|
+
*/
|
|
13
|
+
export interface ToolResult {
|
|
14
|
+
success: boolean;
|
|
15
|
+
error?: string;
|
|
16
|
+
[key: string]: unknown;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* MCP tool response type
|
|
20
|
+
*/
|
|
21
|
+
export type McpToolResponse = {
|
|
22
|
+
content: Array<{
|
|
23
|
+
type: 'text';
|
|
24
|
+
text: string;
|
|
25
|
+
}>;
|
|
26
|
+
isError?: true;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Creates a tool handler wrapper that applies rate limiting and standardizes responses.
|
|
30
|
+
* Eliminates boilerplate code across all tool registrations.
|
|
31
|
+
*/
|
|
32
|
+
export declare function withToolHandler<TArgs, TResult extends ToolResult>(handler: (args: TArgs) => Promise<TResult>, errorMessage: string): (args: TArgs) => Promise<McpToolResponse>;
|
|
33
|
+
/**
|
|
34
|
+
* Create and configure the MCP server with all tools registered.
|
|
35
|
+
*
|
|
36
|
+
* @returns Configured McpServer instance ready to connect to a transport
|
|
37
|
+
*/
|
|
38
|
+
export declare function createServer(): McpServer;
|
|
39
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAkBpE,eAAO,MAAM,WAAW,QAAmB,CAAC;AAC5C,eAAO,MAAM,cAAc,QAAsB,CAAC;AAElD;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,EAAE,IAAI,CAAC;CAChB,CAAC;AAEF;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,SAAS,UAAU,EAC/D,OAAO,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,OAAO,CAAC,OAAO,CAAC,EAC1C,YAAY,EAAE,MAAM,GACnB,CAAC,IAAI,EAAE,KAAK,KAAK,OAAO,CAAC,eAAe,CAAC,CA4B3C;AAED;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,SAAS,CAyIxC"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Server Factory
|
|
3
|
+
*
|
|
4
|
+
* Creates and configures the MCP server with all tools registered.
|
|
5
|
+
* Extracted from index.ts for testability.
|
|
6
|
+
*/
|
|
7
|
+
import { createRequire } from 'module';
|
|
8
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
import { executeQueryTool } from './tools/query.js';
|
|
11
|
+
import { listSchemasTool, listTablesTool, describeTableTool, listViewsTool, listIndexesTool, getTableConstraintsTool, } from './tools/metadata.js';
|
|
12
|
+
import { getRateLimiter } from './utils/rateLimiter.js';
|
|
13
|
+
// Read version from package.json to keep it in sync with npm releases
|
|
14
|
+
const require = createRequire(import.meta.url);
|
|
15
|
+
const packageJson = require('../package.json');
|
|
16
|
+
export const SERVER_NAME = packageJson.name;
|
|
17
|
+
export const SERVER_VERSION = packageJson.version;
|
|
18
|
+
/**
|
|
19
|
+
* Creates a tool handler wrapper that applies rate limiting and standardizes responses.
|
|
20
|
+
* Eliminates boilerplate code across all tool registrations.
|
|
21
|
+
*/
|
|
22
|
+
export function withToolHandler(handler, errorMessage) {
|
|
23
|
+
return async (args) => {
|
|
24
|
+
// Check rate limit
|
|
25
|
+
const rateLimiter = getRateLimiter();
|
|
26
|
+
const rateResult = rateLimiter.checkLimit();
|
|
27
|
+
if (!rateResult.allowed) {
|
|
28
|
+
const error = rateLimiter.formatError(rateResult);
|
|
29
|
+
return {
|
|
30
|
+
content: [{ type: 'text', text: JSON.stringify(error, null, 2) }],
|
|
31
|
+
isError: true,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
// Execute the tool
|
|
35
|
+
const result = await handler(args);
|
|
36
|
+
if (!result.success) {
|
|
37
|
+
return {
|
|
38
|
+
content: [{ type: 'text', text: result.error ?? errorMessage }],
|
|
39
|
+
isError: true,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Create and configure the MCP server with all tools registered.
|
|
49
|
+
*
|
|
50
|
+
* @returns Configured McpServer instance ready to connect to a transport
|
|
51
|
+
*/
|
|
52
|
+
export function createServer() {
|
|
53
|
+
const server = new McpServer({
|
|
54
|
+
name: SERVER_NAME,
|
|
55
|
+
version: SERVER_VERSION,
|
|
56
|
+
});
|
|
57
|
+
// Register execute_query tool
|
|
58
|
+
server.registerTool('execute_query', {
|
|
59
|
+
title: 'Execute SQL Query',
|
|
60
|
+
description: 'Execute a read-only SQL SELECT query against the IBM DB2i database. Only SELECT statements are allowed for security. Results are limited by default to prevent large result sets.',
|
|
61
|
+
annotations: { readOnlyHint: true },
|
|
62
|
+
inputSchema: {
|
|
63
|
+
sql: z.string().describe('SQL SELECT query to execute'),
|
|
64
|
+
params: z.array(z.unknown()).optional().describe('Query parameters for prepared statement'),
|
|
65
|
+
limit: z.number().optional().default(1000).describe('Maximum number of rows to return (default: 1000)'),
|
|
66
|
+
},
|
|
67
|
+
}, withToolHandler((args) => executeQueryTool({
|
|
68
|
+
sql: args.sql,
|
|
69
|
+
params: args.params,
|
|
70
|
+
limit: args.limit ?? 1000,
|
|
71
|
+
}), 'Query failed'));
|
|
72
|
+
// Register list_schemas tool
|
|
73
|
+
server.registerTool('list_schemas', {
|
|
74
|
+
title: 'List Schemas',
|
|
75
|
+
description: 'List all schemas (libraries) in the IBM DB2i database. Optionally filter by name pattern using * as wildcard.',
|
|
76
|
+
annotations: { readOnlyHint: true },
|
|
77
|
+
inputSchema: {
|
|
78
|
+
filter: z.string().optional().describe('Filter pattern for schema names. Use * as wildcard. Example: "QSYS*" matches schemas starting with QSYS'),
|
|
79
|
+
},
|
|
80
|
+
}, withToolHandler((args) => listSchemasTool({ filter: args.filter }), 'Failed to list schemas'));
|
|
81
|
+
// Register list_tables tool
|
|
82
|
+
server.registerTool('list_tables', {
|
|
83
|
+
title: 'List Tables',
|
|
84
|
+
description: 'List all tables in a schema (library). Uses DB2I_SCHEMA env var if schema not provided. Optionally filter by name pattern using * as wildcard.',
|
|
85
|
+
annotations: { readOnlyHint: true },
|
|
86
|
+
inputSchema: {
|
|
87
|
+
schema: z.string().optional().describe('Schema (library) name to list tables from. Uses DB2I_SCHEMA env var if not provided.'),
|
|
88
|
+
filter: z.string().optional().describe('Filter pattern for table names. Use * as wildcard. Example: "CUST*" matches tables starting with CUST'),
|
|
89
|
+
},
|
|
90
|
+
}, withToolHandler((args) => listTablesTool({ schema: args.schema, filter: args.filter }), 'Failed to list tables'));
|
|
91
|
+
// Register describe_table tool
|
|
92
|
+
server.registerTool('describe_table', {
|
|
93
|
+
title: 'Describe Table',
|
|
94
|
+
description: 'Get detailed column information for a specific table including data types, lengths, nullability, defaults, and CCSID. Uses DB2I_SCHEMA env var if schema not provided.',
|
|
95
|
+
annotations: { readOnlyHint: true },
|
|
96
|
+
inputSchema: {
|
|
97
|
+
schema: z.string().optional().describe('Schema (library) name containing the table. Uses DB2I_SCHEMA env var if not provided.'),
|
|
98
|
+
table: z.string().describe('Table name to describe'),
|
|
99
|
+
},
|
|
100
|
+
}, withToolHandler((args) => describeTableTool({ schema: args.schema, table: args.table }), 'Failed to describe table'));
|
|
101
|
+
// Register list_views tool
|
|
102
|
+
server.registerTool('list_views', {
|
|
103
|
+
title: 'List Views',
|
|
104
|
+
description: 'List all views in a schema (library). Uses DB2I_SCHEMA env var if schema not provided. Optionally filter by name pattern using * as wildcard.',
|
|
105
|
+
annotations: { readOnlyHint: true },
|
|
106
|
+
inputSchema: {
|
|
107
|
+
schema: z.string().optional().describe('Schema (library) name to list views from. Uses DB2I_SCHEMA env var if not provided.'),
|
|
108
|
+
filter: z.string().optional().describe('Filter pattern for view names. Use * as wildcard.'),
|
|
109
|
+
},
|
|
110
|
+
}, withToolHandler((args) => listViewsTool({ schema: args.schema, filter: args.filter }), 'Failed to list views'));
|
|
111
|
+
// Register list_indexes tool
|
|
112
|
+
server.registerTool('list_indexes', {
|
|
113
|
+
title: 'List Indexes',
|
|
114
|
+
description: 'List all indexes for a specific table including uniqueness and column information. Uses DB2I_SCHEMA env var if schema not provided.',
|
|
115
|
+
annotations: { readOnlyHint: true },
|
|
116
|
+
inputSchema: {
|
|
117
|
+
schema: z.string().optional().describe('Schema (library) name containing the table. Uses DB2I_SCHEMA env var if not provided.'),
|
|
118
|
+
table: z.string().describe('Table name to list indexes for'),
|
|
119
|
+
},
|
|
120
|
+
}, withToolHandler((args) => listIndexesTool({ schema: args.schema, table: args.table }), 'Failed to list indexes'));
|
|
121
|
+
// Register get_table_constraints tool
|
|
122
|
+
server.registerTool('get_table_constraints', {
|
|
123
|
+
title: 'Get Table Constraints',
|
|
124
|
+
description: 'Get all constraints (primary keys, foreign keys, unique constraints) for a specific table. Uses DB2I_SCHEMA env var if schema not provided.',
|
|
125
|
+
annotations: { readOnlyHint: true },
|
|
126
|
+
inputSchema: {
|
|
127
|
+
schema: z.string().optional().describe('Schema (library) name containing the table. Uses DB2I_SCHEMA env var if not provided.'),
|
|
128
|
+
table: z.string().describe('Table name to get constraints for'),
|
|
129
|
+
},
|
|
130
|
+
}, withToolHandler((args) => getTableConstraintsTool({ schema: args.schema, table: args.table }), 'Failed to get constraints'));
|
|
131
|
+
return server;
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EACL,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,uBAAuB,GACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,sEAAsE;AACtE,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,WAAW,GAAG,OAAO,CAAC,iBAAiB,CAAsC,CAAC;AAEpF,MAAM,CAAC,MAAM,WAAW,GAAG,WAAW,CAAC,IAAI,CAAC;AAC5C,MAAM,CAAC,MAAM,cAAc,GAAG,WAAW,CAAC,OAAO,CAAC;AAmBlD;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC7B,OAA0C,EAC1C,YAAoB;IAEpB,OAAO,KAAK,EAAE,IAAW,EAA4B,EAAE;QACrD,mBAAmB;QACnB,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;QACrC,MAAM,UAAU,GAAG,WAAW,CAAC,UAAU,EAAE,CAAC;QAE5C,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;YACxB,MAAM,KAAK,GAAG,WAAW,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;YAClD,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;gBACjE,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QAED,mBAAmB;QACnB,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;QAEnC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,KAAK,IAAI,YAAY,EAAE,CAAC;gBAC/D,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QAED,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;SACnE,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,cAAc;KACxB,CAAC,CAAC;IAEH,8BAA8B;IAC9B,MAAM,CAAC,YAAY,CACjB,eAAe,EACf;QACE,KAAK,EAAE,mBAAmB;QAC1B,WAAW,EAAE,mLAAmL;QAChM,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE;QACnC,WAAW,EAAE;YACX,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,6BAA6B,CAAC;YACvD,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,yCAAyC,CAAC;YAC3F,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,kDAAkD,CAAC;SACxG;KACF,EACD,eAAe,CACb,CAAC,IAAI,EAAE,EAAE,CAAC,gBAAgB,CAAC;QACzB,GAAG,EAAE,IAAI,CAAC,GAAG;QACb,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,IAAI;KAC1B,CAAC,EACF,cAAc,CACf,CACF,CAAC;IAEF,6BAA6B;IAC7B,MAAM,CAAC,YAAY,CACjB,cAAc,EACd;QACE,KAAK,EAAE,cAAc;QACrB,WAAW,EAAE,+GAA+G;QAC5H,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE;QACnC,WAAW,EAAE;YACX,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,yGAAyG,CAAC;SAClJ;KACF,EACD,eAAe,CACb,CAAC,IAAI,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,EAClD,wBAAwB,CACzB,CACF,CAAC;IAEF,4BAA4B;IAC5B,MAAM,CAAC,YAAY,CACjB,aAAa,EACb;QACE,KAAK,EAAE,aAAa;QACpB,WAAW,EAAE,gJAAgJ;QAC7J,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE;QACnC,WAAW,EAAE;YACX,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,sFAAsF,CAAC;YAC9H,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,uGAAuG,CAAC;SAChJ;KACF,EACD,eAAe,CACb,CAAC,IAAI,EAAE,EAAE,CAAC,cAAc,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,EACtE,uBAAuB,CACxB,CACF,CAAC;IAEF,+BAA+B;IAC/B,MAAM,CAAC,YAAY,CACjB,gBAAgB,EAChB;QACE,KAAK,EAAE,gBAAgB;QACvB,WAAW,EAAE,wKAAwK;QACrL,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE;QACnC,WAAW,EAAE;YACX,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,uFAAuF,CAAC;YAC/H,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wBAAwB,CAAC;SACrD;KACF,EACD,eAAe,CACb,CAAC,IAAI,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,EACvE,0BAA0B,CAC3B,CACF,CAAC;IAEF,2BAA2B;IAC3B,MAAM,CAAC,YAAY,CACjB,YAAY,EACZ;QACE,KAAK,EAAE,YAAY;QACnB,WAAW,EAAE,+IAA+I;QAC5J,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE;QACnC,WAAW,EAAE;YACX,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qFAAqF,CAAC;YAC7H,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mDAAmD,CAAC;SAC5F;KACF,EACD,eAAe,CACb,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,EACrE,sBAAsB,CACvB,CACF,CAAC;IAEF,6BAA6B;IAC7B,MAAM,CAAC,YAAY,CACjB,cAAc,EACd;QACE,KAAK,EAAE,cAAc;QACrB,WAAW,EAAE,qIAAqI;QAClJ,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE;QACnC,WAAW,EAAE;YACX,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,uFAAuF,CAAC;YAC/H,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gCAAgC,CAAC;SAC7D;KACF,EACD,eAAe,CACb,CAAC,IAAI,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,EACrE,wBAAwB,CACzB,CACF,CAAC;IAEF,sCAAsC;IACtC,MAAM,CAAC,YAAY,CACjB,uBAAuB,EACvB;QACE,KAAK,EAAE,uBAAuB;QAC9B,WAAW,EAAE,6IAA6I;QAC1J,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE;QACnC,WAAW,EAAE;YACX,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,uFAAuF,CAAC;YAC/H,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,mCAAmC,CAAC;SAChE;KACF,EACD,eAAe,CACb,CAAC,IAAI,EAAE,EAAE,CAAC,uBAAuB,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,EAC7E,2BAA2B,CAC5B,CACF,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC"}
|