Skip to main content
Glama
itshare4u

Agent Knowledge MCP

setup_elasticsearch

Deploy Elasticsearch with Docker, optionally adding Kibana and recreating containers as needed for search and analytics.

Instructions

Auto-setup Elasticsearch using Docker with optional Kibana and force recreate options

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
include_kibanaNoAlso setup Kibana (default: true)
force_recreateNoForce recreate containers even if they exist

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • Primary handler for the 'setup_elasticsearch' tool. Manages Docker container lifecycle for Elasticsearch (+Kibana), calls helper auto_setup_elasticsearch, updates config, and reinitializes client.
    @app.tool(
        description="Auto-setup Elasticsearch using Docker with optional Kibana and force recreate options",
        tags={"admin", "elasticsearch", "setup", "docker", "auto-install"}
    )
    async def setup_elasticsearch(
        include_kibana: Annotated[bool, Field(description="Also setup Kibana (default: true)")] = True,
        force_recreate: Annotated[bool, Field(description="Force recreate containers even if they exist")] = False
    ) -> str:
        """Auto-setup Elasticsearch using Docker with comprehensive Docker container management."""
        try:
            # Get config path for setup
            config_path = Path(__file__).parent.parent / "config.json"
            config = load_config()
    
            # Handle force recreate - stop existing containers first
            if force_recreate:
                try:
                    setup_manager = ElasticsearchSetup(config_path)
                    stop_result = setup_manager.stop_containers()
    
                    # Give containers time to stop gracefully
                    import time
                    time.sleep(5)
    
                    message = "šŸ”„ **Force Recreate Mode:**\n"
                    message += f"   šŸ›‘ Stopped existing containers\n"
                    message += f"   ā³ Waiting for graceful shutdown...\n\n"
                except Exception as e:
                    # Continue with setup even if stop fails
                    message = f"āš ļø **Container Stop Warning:** {str(e)}\n"
                    message += f"   šŸ’” Continuing with setup anyway...\n\n"
            else:
                message = ""
    
            # Run comprehensive auto setup
            result = auto_setup_elasticsearch(config_path, config)
    
            if result["status"] == "already_configured":
                message += "āœ… **Elasticsearch Already Configured!**\n\n"
                message += f"šŸ“ **Running at:** http://{result['host']}:{result['port']}\n"
                message += f"šŸ” **Status:** Ready and operational\n"
                message += f"šŸ’” **Action:** No setup needed - already working perfectly\n\n"
                message += f"šŸš€ **Next Steps:**\n"
                message += f"   • Test connection with search tools\n"
                message += f"   • Start indexing your knowledge base\n"
                message += f"   • Use force_recreate=true to rebuild if needed"
    
            elif result["status"] == "setup_completed":
                es_info = result["elasticsearch"]
                kibana_info = result.get("kibana")
    
                message += "šŸŽ‰ **Elasticsearch Setup Completed Successfully!**\n\n"
                message += f"šŸ“ **Elasticsearch:** http://{es_info['host']}:{es_info['port']}\n"
    
                # Handle Kibana setup results
                if kibana_info:
                    if kibana_info.get("status") in ["running", "already_running"]:
                        message += f"šŸ“Š **Kibana:** http://{kibana_info['host']}:{kibana_info['port']}\n"
                        message += f"   āœ… Status: {kibana_info['status'].replace('_', ' ').title()}\n"
                    elif "error" in kibana_info:
                        message += f"āš ļø **Kibana Warning:** {kibana_info['error']}\n"
                        message += f"   šŸ’” Elasticsearch is ready, Kibana setup had issues\n"
                else:
                    message += f"šŸ“Š **Kibana:** Skipped (include_kibana=false)\n"
    
                message += f"\nšŸ”§ **Configuration Updated:**\n"
                message += f"   šŸ“ config.json automatically updated\n"
                message += f"   šŸ”„ Elasticsearch client reinitialized\n"
                message += f"   āœ… All components ready for use\n"
    
                message += f"\nšŸš€ **Next Steps:**\n"
                message += f"   • Test search functionality\n"
                message += f"   • Index your first documents\n"
                message += f"   • Explore Kibana dashboard (if enabled)\n"
    
                # Reload configuration to use new Elasticsearch setup
                new_config = load_config()
                init_elasticsearch(new_config)
                reset_es_client()
    
            else:
                # Setup failed
                error_msg = result.get("error", "Unknown setup error")
                message += f"āŒ **Elasticsearch Setup Failed!**\n\n"
                message += f"🚨 **Error Details:** {error_msg}\n\n"
                message += f"šŸ”§ **Troubleshooting Steps:**\n"
                message += f"   1. Check Docker is running and accessible\n"
                message += f"   2. Verify ports 9200 (ES) and 5601 (Kibana) are available\n"
                message += f"   3. Try force_recreate=true to rebuild containers\n"
                message += f"   4. Check Docker logs for detailed error information\n"
                message += f"   5. Ensure sufficient disk space and memory\n\n"
                message += f"šŸ’” **Need Help?** Check Docker status and container logs for more details"
    
            return message
    
        except ImportError as e:
            return f"āŒ Module Error: Missing required dependency\nšŸ” Details: {str(e)}\nšŸ’” Ensure all Elasticsearch setup modules are properly installed"
        except FileNotFoundError as e:
            return f"āŒ File Error: Required configuration or setup file not found\nšŸ” Details: {str(e)}\nšŸ’” Check config.json exists and setup modules are in place"
        except Exception as e:
            return _format_admin_error(e, "setup Elasticsearch", f"Docker setup with include_kibana={include_kibana}, force_recreate={force_recreate}")
  • Pydantic schema definitions for tool inputs using Annotated[Field]. Defines parameters for Kibana inclusion and force recreate.
    async def setup_elasticsearch(
        include_kibana: Annotated[bool, Field(description="Also setup Kibana (default: true)")] = True,
        force_recreate: Annotated[bool, Field(description="Force recreate containers even if they exist")] = False
    ) -> str:
  • Lists 'setup_elasticsearch' as available tool from Admin Server in CLI output, confirming registration via mounting.
    print("    └─ Tools: get_config, update_config, server_status, server_upgrade, setup_elasticsearch, elasticsearch_status, validate_config, reset_config, reload_config")
  • Core helper function called by the tool handler. Performs Docker setup via ElasticsearchSetup class, updates config.json, returns setup status.
    def auto_setup_elasticsearch(config_path: Path, config: Dict[str, Any]) -> Dict[str, Any]:
        """Auto-setup Elasticsearch if not configured or not accessible."""
        
        # Check if Elasticsearch is already configured and accessible
        if check_elasticsearch_config(config):
            host = config["elasticsearch"]["host"]
            port = config["elasticsearch"]["port"]
            print(f"Elasticsearch already running at {host}:{port}")
            return {"status": "already_configured", "host": host, "port": port}
        
        print("Elasticsearch not accessible, starting auto-setup...")
        
        # Setup Elasticsearch using Docker
        setup = ElasticsearchSetup(config_path)
        
        try:
            result = setup.setup_elasticsearch(include_kibana=True)
            
            # Update config file
            es_host = result["elasticsearch"]["host"]
            es_port = result["elasticsearch"]["port"]
            setup.update_config(es_host, es_port)
            
            print("šŸŽ‰ Elasticsearch setup completed!")
            print(f"šŸ“ Elasticsearch: http://{es_host}:{es_port}")
            
            if result["kibana"] and result["kibana"]["status"] in ["running", "already_running"]:
                kibana_host = result["kibana"]["host"]
                kibana_port = result["kibana"]["port"]
                print(f"šŸ“Š Kibana: http://{kibana_host}:{kibana_port}")
            
            return {
                "status": "setup_completed",
                "elasticsearch": result["elasticsearch"],
                "kibana": result["kibana"]
            }
            
        except Exception as e:
            print(f"āŒ Failed to setup Elasticsearch: {e}")
            return {"status": "setup_failed", "error": str(e)}
  • Supporting class with Docker operations: container management (start/stop/status), config updates, health checks for ES and Kibana.
    class ElasticsearchSetup:
        """Manage Elasticsearch Docker container setup."""
        
        def __init__(self, config_path: Path):
            self.config_path = config_path
            self.docker_client = None
            self.container_name = "elasticsearch-mcp"
            self.kibana_container_name = "kibana-mcp"
            
        def _get_docker_client(self):
            """Get Docker client."""
            if self.docker_client is None:
                try:
                    self.docker_client = docker.from_env()
                    # Test connection
                    self.docker_client.ping()
                except DockerException as e:
                    raise ConnectionError(f"Cannot connect to Docker. Is Docker running? Error: {e}")
            return self.docker_client
        
        def _is_elasticsearch_running(self, host: str, port: int) -> bool:
            """Check if Elasticsearch is running at the given host:port."""
            try:
                response = requests.get(f"http://{host}:{port}", timeout=5)
                return response.status_code == 200
            except:
                return False
        
        def _wait_for_elasticsearch(self, host: str, port: int, timeout: int = 60) -> bool:
            """Wait for Elasticsearch to be ready."""
            print(f"Waiting for Elasticsearch at {host}:{port}...")
            start_time = time.time()
            
            while time.time() - start_time < timeout:
                if self._is_elasticsearch_running(host, port):
                    print("āœ… Elasticsearch is ready!")
                    return True
                time.sleep(2)
                print("ā³ Still waiting...")
            
            print("āŒ Timeout waiting for Elasticsearch")
            return False
        
        def _container_exists(self, container_name: str) -> bool:
            """Check if container exists."""
            try:
                client = self._get_docker_client()
                client.containers.get(container_name)
                return True
            except NotFound:
                return False
        
        def _is_container_running(self, container_name: str) -> bool:
            """Check if container is running."""
            try:
                client = self._get_docker_client()
                container = client.containers.get(container_name)
                return container.status == 'running'
            except NotFound:
                return False
        
        def start_elasticsearch_container(self) -> Dict[str, Any]:
            """Start Elasticsearch container."""
            client = self._get_docker_client()
            
            # Check if container already exists
            if self._container_exists(self.container_name):
                if self._is_container_running(self.container_name):
                    print(f"Container {self.container_name} is already running")
                    return {"status": "already_running", "host": "localhost", "port": 9200}
                else:
                    # Start existing container
                    print(f"šŸ”„ Starting existing container {self.container_name}")
                    container = client.containers.get(self.container_name)
                    container.start()
            else:
                # Create new container
                print(f"šŸš€ Creating new Elasticsearch container {self.container_name}")
                
                environment = {
                    "discovery.type": "single-node",
                    "ES_JAVA_OPTS": "-Xms512m -Xmx512m",
                    "xpack.security.enabled": "false",
                    "xpack.security.enrollment.enabled": "false"
                }
                
                ports = {"9200/tcp": 9200, "9300/tcp": 9300}
                
                container = client.containers.run(
                    "docker.elastic.co/elasticsearch/elasticsearch:8.14.1",
                    name=self.container_name,
                    environment=environment,
                    ports=ports,
                    detach=True,
                    restart_policy={"Name": "unless-stopped"}
                )
                
                print(f"šŸ“¦ Container {self.container_name} created")
            
            # Wait for Elasticsearch to be ready
            if self._wait_for_elasticsearch("localhost", 9200):
                return {"status": "running", "host": "localhost", "port": 9200}
            else:
                raise RuntimeError("Failed to start Elasticsearch within timeout")
        
        def start_kibana_container(self) -> Dict[str, Any]:
            """Start Kibana container."""
            client = self._get_docker_client()
            
            # Check if Elasticsearch is running first
            if not self._is_container_running(self.container_name):
                raise RuntimeError("Elasticsearch container must be running before starting Kibana")
            
            # Check if Kibana container already exists
            if self._container_exists(self.kibana_container_name):
                if self._is_container_running(self.kibana_container_name):
                    print(f"āœ… Container {self.kibana_container_name} is already running")
                    return {"status": "already_running", "host": "localhost", "port": 5601}
                else:
                    # Start existing container
                    print(f"šŸ”„ Starting existing container {self.kibana_container_name}")
                    container = client.containers.get(self.kibana_container_name)
                    container.start()
            else:
                # Create new container
                print(f"šŸš€ Creating new Kibana container {self.kibana_container_name}")
                
                environment = {
                    "ELASTICSEARCH_HOSTS": "http://elasticsearch-mcp:9200"
                }
                
                ports = {"5601/tcp": 5601}
                
                container = client.containers.run(
                    "docker.elastic.co/kibana/kibana:8.14.1",
                    name=self.kibana_container_name,
                    environment=environment,
                    ports=ports,
                    links={self.container_name: "elasticsearch-mcp"},
                    detach=True,
                    restart_policy={"Name": "unless-stopped"}
                )
                
                print(f"šŸ“¦ Container {self.kibana_container_name} created")
            
            # Wait a bit for Kibana to start
            print("ā³ Waiting for Kibana to start...")
            time.sleep(10)
            
            return {"status": "running", "host": "localhost", "port": 5601}
        
        def setup_elasticsearch(self, include_kibana: bool = True) -> Dict[str, Any]:
            """Complete Elasticsearch setup with optional Kibana."""
            print("šŸ”§ Setting up Elasticsearch...")
            
            # Start Elasticsearch
            es_result = self.start_elasticsearch_container()
            
            result = {
                "elasticsearch": es_result,
                "kibana": None
            }
            
            # Start Kibana if requested
            if include_kibana:
                try:
                    kibana_result = self.start_kibana_container()
                    result["kibana"] = kibana_result
                except Exception as e:
                    print(f"āš ļø  Warning: Failed to start Kibana: {e}")
                    result["kibana"] = {"status": "failed", "error": str(e)}
            
            return result
        
        def update_config(self, host: str, port: int) -> None:
            """Update configuration file with Elasticsearch connection details."""
            try:
                # Load current config
                with open(self.config_path, 'r', encoding='utf-8') as f:
                    config = json.load(f)
                
                # Update Elasticsearch settings
                config["elasticsearch"]["host"] = host
                config["elasticsearch"]["port"] = port
                config["elasticsearch"]["auto_setup"] = True
                
                # Save updated config
                with open(self.config_path, 'w', encoding='utf-8') as f:
                    json.dump(config, f, indent=2, ensure_ascii=False)
                
                print(f"āœ… Updated config file: {host}:{port}")
                
            except Exception as e:
                print(f"āŒ Failed to update config: {e}")
                raise
        
        def get_container_status(self) -> Dict[str, Any]:
            """Get status of Elasticsearch and Kibana containers."""
            try:
                client = self._get_docker_client()
                
                status = {
                    "elasticsearch": {
                        "exists": self._container_exists(self.container_name),
                        "running": self._is_container_running(self.container_name),
                        "container_name": self.container_name
                    },
                    "kibana": {
                        "exists": self._container_exists(self.kibana_container_name),
                        "running": self._is_container_running(self.kibana_container_name),
                        "container_name": self.kibana_container_name
                    }
                }
                
                return status
                
            except Exception as e:
                return {"error": str(e)}
        
        def stop_containers(self) -> Dict[str, Any]:
            """Stop Elasticsearch and Kibana containers."""
            try:
                client = self._get_docker_client()
                results = {}
                
                # Stop Kibana first
                if self._container_exists(self.kibana_container_name):
                    container = client.containers.get(self.kibana_container_name)
                    container.stop()
                    results["kibana"] = "stopped"
                
                # Stop Elasticsearch
                if self._container_exists(self.container_name):
                    container = client.containers.get(self.container_name)
                    container.stop()
                    results["elasticsearch"] = "stopped"
                
                return results
                
            except Exception as e:
                return {"error": str(e)}
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries full burden but lacks critical behavioral details. It mentions 'force recreate' as an option but doesn't disclose potential destructive effects, permission requirements, side effects like data loss, or runtime characteristics. This is inadequate for a setup tool that likely involves system changes.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, efficient sentence that front-loads the core purpose and mentions key options without unnecessary words. Every element serves a purpose, making it optimally concise for the information conveyed.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool has an output schema (which handles return values) and 100% schema coverage for parameters, the description is moderately complete. However, as a setup tool with no annotations, it should ideally include more behavioral context about system impact and dependencies to be fully helpful for an agent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents both parameters fully. The description adds minimal value by naming 'Kibana' and 'force recreate' but doesn't provide additional context beyond what's in the schema descriptions. This meets the baseline for high schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('Auto-setup') and resource ('Elasticsearch using Docker'), and mentions optional components ('Kibana') and behaviors ('force recreate'). However, it doesn't explicitly differentiate from sibling tools like 'elasticsearch_status' or 'server_status' that might check rather than setup, leaving some ambiguity.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage for initial setup or reconfiguration with optional features, but provides no explicit guidance on when to use this tool versus alternatives like 'server_upgrade' or 'reset_config', nor any prerequisites or exclusions. This leaves the agent guessing about appropriate contexts.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/itshare4u/AgentKnowledgeMCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server