(toolConfig: ToolConfig)
| 154 | * @returns Handler function compatible with MCP server.registerTool |
| 155 | */ |
| 156 | export function createCustomToolHandler(toolConfig: ToolConfig) { |
| 157 | // Build Zod schema shape for MCP registration |
| 158 | const zodSchemaShape = buildZodSchemaFromParameters(toolConfig.parameters); |
| 159 | // Wrap in z.object() for validation |
| 160 | const zodSchema = z.object(zodSchemaShape); |
| 161 | |
| 162 | return async (args: any, extra: any) => { |
| 163 | const startTime = Date.now(); |
| 164 | let success = true; |
| 165 | let errorMessage: string | undefined; |
| 166 | let paramValues: any[] = []; |
| 167 | |
| 168 | try { |
| 169 | // 1. Validate arguments against Zod schema |
| 170 | const validatedArgs = zodSchema.parse(args); |
| 171 | |
| 172 | // 2. Ensure source is connected (handles lazy connections) |
| 173 | await ConnectorManager.ensureConnected(toolConfig.source); |
| 174 | |
| 175 | // 3. Get connector for the specified source |
| 176 | const connector = ConnectorManager.getCurrentConnector(toolConfig.source); |
| 177 | |
| 178 | // 4. Build execute options from tool configuration |
| 179 | const executeOptions = { |
| 180 | readonly: toolConfig.readonly, |
| 181 | maxRows: toolConfig.max_rows, |
| 182 | }; |
| 183 | |
| 184 | // 5. Check if SQL is allowed based on readonly mode |
| 185 | const isReadonly = executeOptions.readonly === true; |
| 186 | if (isReadonly && !isAllowedInReadonlyMode(toolConfig.statement, connector.id)) { |
| 187 | errorMessage = createReadonlyViolationMessage(toolConfig.name, toolConfig.source, connector.id); |
| 188 | success = false; |
| 189 | return createToolErrorResponse(errorMessage, "READONLY_VIOLATION"); |
| 190 | } |
| 191 | |
| 192 | // 6. Map parameters to array format for SQL execution |
| 193 | paramValues = mapArgumentsToArray( |
| 194 | toolConfig.parameters, |
| 195 | validatedArgs |
| 196 | ); |
| 197 | |
| 198 | // 7. Execute SQL with parameters |
| 199 | const result = await connector.executeSQL( |
| 200 | toolConfig.statement, |
| 201 | executeOptions, |
| 202 | paramValues |
| 203 | ); |
| 204 | |
| 205 | // 8. Build response data |
| 206 | const responseData = { |
| 207 | rows: result.rows, |
| 208 | count: result.rowCount, |
| 209 | source_id: toolConfig.source, |
| 210 | }; |
| 211 | |
| 212 | return createToolSuccessResponse(responseData); |
| 213 | } catch (error) { |
no test coverage detected