UNPKG

elasticsearch-mcp

Version:

Secure MCP server for Elasticsearch integration with comprehensive tools and Elastic Cloud support

140 lines 6.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CreateIndexTool = void 0; const schemas_js_1 = require("../validation/schemas.js"); const handlers_js_1 = require("../errors/handlers.js"); class CreateIndexTool { elasticsearch; logger; constructor(elasticsearch, logger) { this.elasticsearch = elasticsearch; this.logger = logger.child({ tool: 'create-index' }); } async execute(args) { try { const validatedArgs = schemas_js_1.CreateIndexArgsSchema.parse(args); this.logger.info('Creating index', { name: validatedArgs.name, hasMappings: !!validatedArgs.mappings, hasSettings: !!validatedArgs.settings, aliasCount: validatedArgs.aliases?.length || 0, }); const client = this.elasticsearch.getClient(); // Check if index already exists const exists = await client.indices.exists({ index: validatedArgs.name, }); if (exists) { throw new handlers_js_1.ValidationError(`Index '${validatedArgs.name}' already exists`); } // Prepare index body const indexBody = {}; if (validatedArgs.mappings) { indexBody.mappings = this.validateMappings(validatedArgs.mappings); } if (validatedArgs.settings) { indexBody.settings = this.validateSettings(validatedArgs.settings); } if (validatedArgs.aliases && validatedArgs.aliases.length > 0) { indexBody.aliases = this.buildAliases(validatedArgs.aliases); } // Create the index const response = await client.indices.create({ index: validatedArgs.name, body: indexBody, }); this.logger.info('Successfully created index', { name: validatedArgs.name, acknowledged: response.acknowledged, shardsAcknowledged: response.shards_acknowledged, }); return { acknowledged: response.acknowledged, index: validatedArgs.name, shardsAcknowledged: response.shards_acknowledged, }; } catch (error) { if (error instanceof Error && error.name === 'ZodError') { throw new handlers_js_1.ValidationError('Invalid arguments for create_index', { details: error.message, }); } if (error instanceof handlers_js_1.ValidationError) { throw error; } this.logger.error('Failed to create index', {}, error); throw new handlers_js_1.ElasticsearchError('Failed to create index in Elasticsearch', error, { args }); } } validateMappings(mappings) { // Basic validation for mappings structure if (typeof mappings !== 'object' || Array.isArray(mappings)) { throw new handlers_js_1.ValidationError('Mappings must be a valid object'); } // Check for common mapping structure if (mappings.properties && typeof mappings.properties !== 'object') { throw new handlers_js_1.ValidationError('Mappings properties must be an object'); } // Validate property types if (mappings.properties) { this.validateMappingProperties(mappings.properties); } return mappings; } validateMappingProperties(properties) { const validFieldTypes = [ 'text', 'keyword', 'integer', 'long', 'float', 'double', 'boolean', 'date', 'ip', 'geo_point', 'geo_shape', 'nested', 'object', 'binary', 'integer_range', 'float_range', 'long_range', 'double_range', 'date_range', 'ip_range', ]; for (const [fieldName, fieldConfig] of Object.entries(properties)) { if (typeof fieldConfig === 'object' && fieldConfig !== null) { const config = fieldConfig; if (config.type && typeof config.type === 'string') { if (!validFieldTypes.includes(config.type)) { throw new handlers_js_1.ValidationError(`Invalid field type '${config.type}' for field '${fieldName}'`); } } // Recursively validate nested properties if (config.properties) { this.validateMappingProperties(config.properties); } } } } validateSettings(settings) { // Basic validation for settings structure if (typeof settings !== 'object' || Array.isArray(settings)) { throw new handlers_js_1.ValidationError('Settings must be a valid object'); } // Validate critical settings if (settings.number_of_shards && typeof settings.number_of_shards === 'number') { if (settings.number_of_shards < 1 || settings.number_of_shards > 1024) { throw new handlers_js_1.ValidationError('Number of shards must be between 1 and 1024'); } } if (settings.number_of_replicas && typeof settings.number_of_replicas === 'number') { if (settings.number_of_replicas < 0 || settings.number_of_replicas > 10) { throw new handlers_js_1.ValidationError('Number of replicas must be between 0 and 10'); } } return settings; } buildAliases(aliases) { const aliasObject = {}; for (const alias of aliases) { if (typeof alias !== 'string' || alias.trim().length === 0) { throw new handlers_js_1.ValidationError('All aliases must be non-empty strings'); } // Validate alias name if (alias.includes(' ') || alias.includes('\t') || alias.includes('\n')) { throw new handlers_js_1.ValidationError(`Invalid alias name '${alias}': cannot contain whitespace`); } aliasObject[alias.trim()] = {}; } return aliasObject; } } exports.CreateIndexTool = CreateIndexTool; //# sourceMappingURL=create-index.js.map