This is an automated email from the ASF dual-hosted git repository.

acosentino pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new f55c086a7197 CAMEL-22960 - Camel-Jbang: Add an harden command and the 
related tool to camel-jbang-mcp (#21267)
f55c086a7197 is described below

commit f55c086a7197327c8bb7e6d804d45deb30534adc
Author: Andrea Cosentino <[email protected]>
AuthorDate: Thu Feb 5 15:03:34 2026 +0100

    CAMEL-22960 - Camel-Jbang: Add an harden command and the related tool to 
camel-jbang-mcp (#21267)
    
    Signed-off-by: Andrea Cosentino <[email protected]>
---
 .../pages/jbang-commands/camel-jbang-commands.adoc |   1 +
 .../pages/jbang-commands/camel-jbang-harden.adoc   |  40 ++
 .../partials/jbang-commands/examples/harden.adoc   | 161 +++++
 .../META-INF/camel-jbang-commands-metadata.json    |   1 +
 .../dsl/jbang/core/commands/CamelJBangMain.java    |   1 +
 .../camel/dsl/jbang/core/commands/Harden.java      | 679 +++++++++++++++++++++
 .../dsl/jbang/core/commands/mcp/HardenTools.java   | 452 ++++++++++++++
 .../src/main/resources/application.properties      |   3 +
 8 files changed, 1338 insertions(+)

diff --git 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-commands.adoc 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-commands.adoc
index d519eb557fe6..179bbddbfaa8 100644
--- 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-commands.adoc
+++ 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-commands.adoc
@@ -23,6 +23,7 @@ TIP: You can also use `camel --help` or `camel <command> 
--help` to see availabl
 | xref:jbang-commands/camel-jbang-explain.adoc[camel explain] | Explain what a 
Camel route does using AI/LLM
 | xref:jbang-commands/camel-jbang-export.adoc[camel export] | Export to other 
runtimes (Camel Main, Spring Boot, or Quarkus)
 | xref:jbang-commands/camel-jbang-get.adoc[camel get] | Get status of Camel 
integrations
+| xref:jbang-commands/camel-jbang-harden.adoc[camel harden] | Suggest security 
hardening for Camel routes using AI/LLM
 | xref:jbang-commands/camel-jbang-hawtio.adoc[camel hawtio] | Launch Hawtio 
web console
 | xref:jbang-commands/camel-jbang-infra.adoc[camel infra] | List and Run 
external services for testing and prototyping
 | xref:jbang-commands/camel-jbang-init.adoc[camel init] | Creates a new Camel 
integration
diff --git 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-harden.adoc 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-harden.adoc
new file mode 100644
index 000000000000..f1d0e9f1b7ca
--- /dev/null
+++ b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-harden.adoc
@@ -0,0 +1,40 @@
+
+// AUTO-GENERATED by camel-package-maven-plugin - DO NOT EDIT THIS FILE
+= camel harden
+
+Suggest security hardening for Camel routes using AI/LLM
+
+
+== Usage
+
+[source,bash]
+----
+camel harden [options]
+----
+
+
+
+== Options
+
+[cols="2,5,1,2",options="header"]
+|===
+| Option | Description | Default | Type
+| `--api-key` | API key for authentication. Also reads OPENAI_API_KEY or 
LLM_API_KEY env vars |  | String
+| `--api-type` | API type: 'ollama' or 'openai' (OpenAI-compatible) | ollama | 
ApiType
+| `--catalog-context` | Include Camel Catalog descriptions in the prompt |  | 
boolean
+| `--format` | Output format: text, markdown | text | String
+| `--model` | Model to use | DEFAULT_MODEL | String
+| `--show-prompt` | Show the prompt sent to the LLM |  | boolean
+| `--stream` | Stream the response as it's generated (shows progress) | true | 
boolean
+| `--system-prompt` | Custom system prompt |  | String
+| `--temperature` | Temperature for response generation (0.0-2.0) | 0.7 | 
double
+| `--timeout` | Timeout in seconds for LLM response | 120 | int
+| `--url` | LLM API endpoint URL. Auto-detected from 'camel infra' for Ollama 
if not specified. |  | String
+| `--verbose,-v` | Include detailed security recommendations with code 
examples |  | boolean
+| `-h,--help` | Display the help and sub-commands |  | boolean
+|===
+
+
+
+include::partial$jbang-commands/examples/harden.adoc[]
+
diff --git 
a/docs/user-manual/modules/ROOT/partials/jbang-commands/examples/harden.adoc 
b/docs/user-manual/modules/ROOT/partials/jbang-commands/examples/harden.adoc
new file mode 100644
index 000000000000..266cc2f1a3a7
--- /dev/null
+++ b/docs/user-manual/modules/ROOT/partials/jbang-commands/examples/harden.adoc
@@ -0,0 +1,161 @@
+== Examples
+
+The `camel harden` command uses AI/LLM to analyze Camel routes and provide 
security hardening recommendations.
+It supports multiple LLM providers including Ollama (local), OpenAI, Azure 
OpenAI, vLLM, LM Studio, and LocalAI.
+
+=== Prerequisites
+
+Start Ollama locally using Camel infra:
+
+[source,bash]
+----
+camel infra run ollama
+----
+
+=== Basic Usage
+
+Analyze a YAML route for security issues:
+
+[source,bash]
+----
+camel harden my-route.yaml
+----
+
+Analyze a Java route:
+
+[source,bash]
+----
+camel harden OrderRoute.java
+----
+
+Analyze multiple route files:
+
+[source,bash]
+----
+camel harden route1.yaml route2.xml MyRoute.java
+----
+
+=== Security Analysis Focus
+
+The harden command analyzes routes for these security concerns:
+
+* **Authentication & Authorization** - Missing or weak authentication, 
credential exposure
+* **Encryption & Data Protection** - TLS/SSL configuration, data in transit 
security
+* **Secrets Management** - Hardcoded credentials, vault integration 
recommendations
+* **Input Validation & Injection Prevention** - SQL, command, and path 
traversal vulnerabilities
+* **Secure Component Configuration** - Insecure defaults, missing security 
headers
+* **Logging & Monitoring** - Sensitive data in logs, audit trail 
recommendations
+
+=== Output Options
+
+Use verbose mode for detailed recommendations with code examples:
+
+[source,bash]
+----
+camel harden my-route.yaml --verbose
+----
+
+Output as Markdown for documentation:
+
+[source,bash]
+----
+camel harden my-route.yaml --format=markdown
+----
+
+=== Prompt Options
+
+Include Camel Catalog descriptions for component-specific security advice:
+
+[source,bash]
+----
+camel harden my-route.yaml --catalog-context
+----
+
+Show the prompt sent to the LLM (useful for debugging):
+
+[source,bash]
+----
+camel harden my-route.yaml --show-prompt
+----
+
+Use a custom system prompt:
+
+[source,bash]
+----
+camel harden my-route.yaml --system-prompt="Focus on OWASP Top 10 
vulnerabilities."
+----
+
+=== LLM Configuration
+
+Use OpenAI or compatible services:
+
+[source,bash]
+----
+camel harden my-route.yaml --url=https://api.openai.com --api-type=openai 
--api-key=sk-...
+----
+
+Use environment variables for the API key:
+
+[source,bash]
+----
+export OPENAI_API_KEY=sk-...
+camel harden my-route.yaml --url=https://api.openai.com --api-type=openai
+----
+
+Use a specific model:
+
+[source,bash]
+----
+camel harden my-route.yaml --model=llama3.1:70b
+----
+
+=== Advanced Options
+
+Disable streaming (wait for complete response):
+
+[source,bash]
+----
+camel harden my-route.yaml --stream=false
+----
+
+Adjust temperature (0.0 = deterministic, 2.0 = creative):
+
+[source,bash]
+----
+camel harden my-route.yaml --temperature=0.3
+----
+
+Set a custom timeout (in seconds):
+
+[source,bash]
+----
+camel harden my-route.yaml --timeout=300
+----
+
+=== Security Findings Severity Levels
+
+The harden command categorizes findings by severity:
+
+* **Critical** - Immediate security risks (command injection, hardcoded 
credentials, disabled TLS)
+* **High** - Significant security concerns (HTTP instead of HTTPS, SQL 
injection risk, plain FTP)
+* **Medium** - Moderate security issues (missing authentication hints, path 
validation concerns)
+* **Low** - Minor security improvements (missing optional security headers)
+
+=== Example Workflow
+
+A typical security review workflow:
+
+[source,bash]
+----
+# 1. First, understand what the route does
+camel explain my-route.yaml
+
+# 2. Perform security analysis
+camel harden my-route.yaml
+
+# 3. Get detailed recommendations with code examples
+camel harden my-route.yaml --verbose --format=markdown
+
+# 4. Full analysis with catalog context
+camel harden my-route.yaml --catalog-context --verbose
+----
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
 
b/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
index bc094d14443a..49a490218e55 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
@@ -12,6 +12,7 @@
     { "name": "explain", "fullName": "explain", "description": "Explain what a 
Camel route does using AI\/LLM", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.Explain", "options": [ { "names": 
"--api-key", "description": "API key for authentication. Also reads 
OPENAI_API_KEY or LLM_API_KEY env vars", "javaType": "java.lang.String", 
"type": "string" }, { "names": "--api-type", "description": "API type: 'ollama' 
or 'openai' (OpenAI-compatible)", "defaultValue": "ollama", "javaTyp [...]
     { "name": "export", "fullName": "export", "description": "Export to other 
runtimes (Camel Main, Spring Boot, or Quarkus)", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.Export", "options": [ { "names": 
"--build-property", "description": "Maven\/Gradle build properties, ex. 
--build-property=prop1=foo", "javaType": "java.util.List", "type": "array" }, { 
"names": "--build-tool", "description": "DEPRECATED: Build tool to use (maven 
or gradle) (gradle is deprecated)", "defaultV [...]
     { "name": "get", "fullName": "get", "description": "Get status of Camel 
integrations", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.process.CamelStatus", "options": [ { 
"names": "--watch", "description": "Execute periodically and showing output 
fullscreen", "javaType": "boolean", "type": "boolean" }, { "names": 
"-h,--help", "description": "Display the help and sub-commands", "javaType": 
"boolean", "type": "boolean" } ], "subcommands": [ { "name": "bean", 
"fullName": "get  [...]
+    { "name": "harden", "fullName": "harden", "description": "Suggest security 
hardening for Camel routes using AI\/LLM", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.Harden", "options": [ { "names": 
"--api-key", "description": "API key for authentication. Also reads 
OPENAI_API_KEY or LLM_API_KEY env vars", "javaType": "java.lang.String", 
"type": "string" }, { "names": "--api-type", "description": "API type: 'ollama' 
or 'openai' (OpenAI-compatible)", "defaultValue": "ollama", [...]
     { "name": "hawtio", "fullName": "hawtio", "description": "Launch Hawtio 
web console", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.process.Hawtio", "options": [ { 
"names": "--openUrl", "description": "To automatic open Hawtio web console in 
the web browser", "defaultValue": "true", "javaType": "boolean", "type": 
"boolean" }, { "names": "--port", "description": "Port number to use for Hawtio 
web console (port 8888 by default)", "defaultValue": "8888", "javaType": "int", 
"t [...]
     { "name": "infra", "fullName": "infra", "description": "List and Run 
external services for testing and prototyping", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.infra.InfraCommand", "options": [ { 
"names": "--json", "description": "Output in JSON Format", "javaType": 
"boolean", "type": "boolean" }, { "names": "-h,--help", "description": "Display 
the help and sub-commands", "javaType": "boolean", "type": "boolean" } ], 
"subcommands": [ { "name": "get", "fullName": "infra  [...]
     { "name": "init", "fullName": "init", "description": "Creates a new Camel 
integration", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Init", 
"options": [ { "names": "--clean-dir,--clean-directory", "description": 
"Whether to clean directory first (deletes all files in directory)", 
"javaType": "boolean", "type": "boolean" }, { "names": "--dir,--directory", 
"description": "Directory relative path where the new Camel integration will be 
saved", "defaultValue": ".", "javaType" [...]
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
index 885d8d490dfd..c62c219295e8 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
@@ -127,6 +127,7 @@ public class CamelJBangMain implements Callable<Integer> {
                 .addSubcommand("dirty", new CommandLine(new Dirty(main)))
                 .addSubcommand("export", new CommandLine(new Export(main)))
                 .addSubcommand("explain", new CommandLine(new Explain(main)))
+                .addSubcommand("harden", new CommandLine(new Harden(main)))
                 .addSubcommand("get", new CommandLine(new CamelStatus(main))
                         .addSubcommand("bean", new CommandLine(new 
CamelBeanDump(main)))
                         .addSubcommand("blocked", new CommandLine(new 
ListBlocked(main)))
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Harden.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Harden.java
new file mode 100644
index 000000000000..244d03619b5b
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Harden.java
@@ -0,0 +1,679 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.dsl.jbang.core.commands;
+
+import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.time.Duration;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.BiFunction;
+import java.util.stream.Stream;
+
+import org.apache.camel.catalog.CamelCatalog;
+import org.apache.camel.catalog.DefaultCamelCatalog;
+import org.apache.camel.dsl.jbang.core.common.CommandLineHelper;
+import org.apache.camel.tooling.model.ComponentModel;
+import org.apache.camel.util.FileUtil;
+import org.apache.camel.util.json.JsonArray;
+import org.apache.camel.util.json.JsonObject;
+import org.apache.camel.util.json.Jsoner;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Option;
+import picocli.CommandLine.Parameters;
+
+/**
+ * Command to suggest security hardening improvements for Camel routes using 
AI/LLM services.
+ * <p>
+ * Analyzes routes for security vulnerabilities, authentication issues, 
encryption gaps, secrets management, input
+ * validation, and other security best practices. Supports multiple LLM 
providers: Ollama, OpenAI, Azure OpenAI, vLLM,
+ * LM Studio, LocalAI, etc.
+ */
+@Command(name = "harden",
+         description = "Suggest security hardening for Camel routes using 
AI/LLM",
+         sortOptions = false, showDefaultValues = true)
+public class Harden extends CamelCommand {
+
+    private static final String DEFAULT_OLLAMA_URL = "http://localhost:11434";;
+    private static final String DEFAULT_MODEL = "llama3.2";
+    private static final int CONNECT_TIMEOUT_SECONDS = 10;
+    private static final int HEALTH_CHECK_TIMEOUT_SECONDS = 5;
+
+    // Components with significant security considerations
+    private static final List<String> SECURITY_SENSITIVE_COMPONENTS = 
Arrays.asList(
+            // Network/API components - need TLS, authentication
+            "http", "https", "netty-http", "vertx-http", "websocket",
+            "rest", "rest-api", "platform-http", "servlet", "undertow", 
"jetty",
+            // Messaging - need authentication, encryption
+            "kafka", "jms", "activemq", "amqp", "rabbitmq", "pulsar",
+            "aws2-sqs", "aws2-sns", "aws2-kinesis",
+            "azure-servicebus", "azure-eventhubs",
+            "google-pubsub",
+            // File/Storage - need access control, path validation
+            "file", "ftp", "sftp", "ftps",
+            "aws2-s3", "azure-storage-blob", "azure-storage-queue", 
"azure-files",
+            "google-storage", "minio",
+            // Database - need authentication, SQL injection prevention
+            "sql", "jdbc", "mongodb", "couchdb", "cassandraql",
+            "elasticsearch", "opensearch", "redis",
+            // Email - need authentication, TLS
+            "smtp", "smtps", "imap", "imaps", "pop3", "pop3s",
+            // Remote execution - high risk, need strict validation
+            "exec", "ssh", "docker",
+            // Directory services - need secure binding
+            "ldap", "ldaps",
+            // Secrets management
+            "hashicorp-vault", "aws2-secrets-manager", "azure-key-vault", 
"google-secret-manager");
+
+    // Security-related categories
+    private static final List<String> OWASP_CATEGORIES = Arrays.asList(
+            "Injection (SQL, Command, LDAP, XPath)",
+            "Broken Authentication",
+            "Sensitive Data Exposure",
+            "XML External Entities (XXE)",
+            "Broken Access Control",
+            "Security Misconfiguration",
+            "Cross-Site Scripting (XSS)",
+            "Insecure Deserialization",
+            "Using Components with Known Vulnerabilities",
+            "Insufficient Logging & Monitoring");
+
+    enum ApiType {
+        ollama((harden, prompts) -> harden.callOllama(prompts[0], prompts[1], 
prompts[2])),
+        openai((harden, prompts) -> harden.callOpenAiCompatible(prompts[0], 
prompts[1], prompts[2], prompts[3]));
+
+        private final BiFunction<Harden, String[], String> caller;
+
+        ApiType(BiFunction<Harden, String[], String> caller) {
+            this.caller = caller;
+        }
+
+        String call(Harden harden, String endpoint, String sysPrompt, String 
userPrompt, String apiKey) {
+            return caller.apply(harden, new String[] { endpoint, sysPrompt, 
userPrompt, apiKey });
+        }
+    }
+
+    @Parameters(description = "Route file(s) to analyze for security 
hardening", arity = "1..*")
+    List<String> files;
+
+    @Option(names = { "--url" },
+            description = "LLM API endpoint URL. Auto-detected from 'camel 
infra' for Ollama if not specified.")
+    String url;
+
+    @Option(names = { "--api-type" },
+            description = "API type: 'ollama' or 'openai' (OpenAI-compatible)",
+            defaultValue = "ollama")
+    ApiType apiType = ApiType.ollama;
+
+    @Option(names = { "--api-key" },
+            description = "API key for authentication. Also reads 
OPENAI_API_KEY or LLM_API_KEY env vars")
+    String apiKey;
+
+    @Option(names = { "--model" },
+            description = "Model to use",
+            defaultValue = DEFAULT_MODEL)
+    String model = DEFAULT_MODEL;
+
+    @Option(names = { "--verbose", "-v" },
+            description = "Include detailed security recommendations with code 
examples")
+    boolean verbose;
+
+    @Option(names = { "--format" },
+            description = "Output format: text, markdown",
+            defaultValue = "text")
+    String format = "text";
+
+    @Option(names = { "--timeout" },
+            description = "Timeout in seconds for LLM response",
+            defaultValue = "120")
+    int timeout = 120;
+
+    @Option(names = { "--catalog-context" },
+            description = "Include Camel Catalog descriptions in the prompt")
+    boolean catalogContext;
+
+    @Option(names = { "--show-prompt" },
+            description = "Show the prompt sent to the LLM")
+    boolean showPrompt;
+
+    @Option(names = { "--temperature" },
+            description = "Temperature for response generation (0.0-2.0)",
+            defaultValue = "0.7")
+    double temperature = 0.7;
+
+    @Option(names = { "--system-prompt" },
+            description = "Custom system prompt")
+    String systemPrompt;
+
+    @Option(names = { "--stream" },
+            description = "Stream the response as it's generated (shows 
progress)",
+            defaultValue = "true")
+    boolean stream = true;
+
+    private final HttpClient httpClient = HttpClient.newBuilder()
+            .connectTimeout(Duration.ofSeconds(CONNECT_TIMEOUT_SECONDS))
+            .build();
+
+    public Harden(CamelJBangMain main) {
+        super(main);
+    }
+
+    @Override
+    public Integer doCall() throws Exception {
+        String endpoint = detectEndpoint();
+        if (endpoint == null) {
+            printUsageHelp();
+            return 1;
+        }
+
+        String resolvedApiKey = resolveApiKey();
+        printConfiguration(endpoint, resolvedApiKey);
+
+        for (String file : files) {
+            int result = hardenRoute(file, endpoint, resolvedApiKey);
+            if (result != 0) {
+                return result;
+            }
+        }
+        return 0;
+    }
+
+    private void printConfiguration(String endpoint, String resolvedApiKey) {
+        printer().println("LLM Configuration:");
+        printer().println("  URL: " + endpoint);
+        printer().println("  API Type: " + apiType);
+        printer().println("  Model: " + model);
+        printMaskedApiKey(resolvedApiKey);
+        printer().println();
+    }
+
+    private void printMaskedApiKey(String key) {
+        if (key == null || key.isBlank()) {
+            return;
+        }
+        String masked = "****" + key.substring(Math.max(0, key.length() - 4));
+        printer().println("  API Key: " + masked);
+    }
+
+    private void printUsageHelp() {
+        printer().printErr("LLM service is not running or not reachable.");
+        printer().printErr("");
+        printer().printErr("Options:");
+        printer().printErr("  1. camel infra run ollama");
+        printer().printErr("  2. camel harden my-route.yaml 
--url=http://localhost:11434";);
+        printer().printErr("  3. camel harden my-route.yaml 
--url=https://api.openai.com --api-type=openai --api-key=sk-...");
+    }
+
+    private String detectEndpoint() {
+        return tryExplicitUrl()
+                .or(this::tryInfraOllama)
+                .or(this::tryDefaultOllama)
+                .orElse(null);
+    }
+
+    private Optional<String> tryExplicitUrl() {
+        if (url == null || url.isBlank()) {
+            return Optional.empty();
+        }
+        if (isEndpointReachable(url)) {
+            return Optional.of(url);
+        }
+        printer().printErr("Cannot connect to LLM service at: " + url);
+        return Optional.empty();
+    }
+
+    private Optional<String> tryInfraOllama() {
+        try {
+            Map<Long, Path> pids = findOllamaPids();
+            for (Path pidFile : pids.values()) {
+                String baseUrl = readBaseUrlFromPidFile(pidFile);
+                if (baseUrl != null && isEndpointReachable(baseUrl)) {
+                    apiType = ApiType.ollama;
+                    return Optional.of(baseUrl);
+                }
+            }
+        } catch (Exception e) {
+            // ignore
+        }
+        return Optional.empty();
+    }
+
+    private String readBaseUrlFromPidFile(Path pidFile) throws Exception {
+        String json = Files.readString(pidFile);
+        JsonObject jo = (JsonObject) Jsoner.deserialize(json);
+        return jo.getString("baseUrl");
+    }
+
+    private Optional<String> tryDefaultOllama() {
+        if (isEndpointReachable(DEFAULT_OLLAMA_URL)) {
+            apiType = ApiType.ollama;
+            return Optional.of(DEFAULT_OLLAMA_URL);
+        }
+        return Optional.empty();
+    }
+
+    private String resolveApiKey() {
+        if (apiKey != null && !apiKey.isBlank()) {
+            return apiKey;
+        }
+        return Stream.of("OPENAI_API_KEY", "LLM_API_KEY")
+                .map(System::getenv)
+                .filter(k -> k != null && !k.isBlank())
+                .findFirst()
+                .orElse(null);
+    }
+
+    private Map<Long, Path> findOllamaPids() throws Exception {
+        Map<Long, Path> pids = new HashMap<>();
+        Path camelDir = CommandLineHelper.getCamelDir();
+
+        if (!Files.exists(camelDir)) {
+            return pids;
+        }
+
+        try (Stream<Path> fileStream = Files.list(camelDir)) {
+            fileStream
+                    .filter(this::isOllamaPidFile)
+                    .forEach(p -> addPidEntry(pids, p));
+        }
+        return pids;
+    }
+
+    private boolean isOllamaPidFile(Path p) {
+        String name = p.getFileName().toString();
+        return name.startsWith("infra-ollama-") && name.endsWith(".json");
+    }
+
+    private void addPidEntry(Map<Long, Path> pids, Path p) {
+        String name = p.getFileName().toString();
+        String pidStr = name.substring(name.lastIndexOf("-") + 1, 
name.lastIndexOf('.'));
+        try {
+            pids.put(Long.valueOf(pidStr), p);
+        } catch (NumberFormatException e) {
+            // ignore
+        }
+    }
+
+    private boolean isEndpointReachable(String endpoint) {
+        return tryHealthCheck(endpoint + "/api/tags")
+                || tryHealthCheck(endpoint + "/v1/models")
+                || tryHealthCheck(endpoint);
+    }
+
+    private boolean tryHealthCheck(String healthUrl) {
+        try {
+            HttpRequest request = HttpRequest.newBuilder()
+                    .uri(URI.create(healthUrl))
+                    .timeout(Duration.ofSeconds(HEALTH_CHECK_TIMEOUT_SECONDS))
+                    .GET()
+                    .build();
+            HttpResponse<String> response = httpClient.send(request, 
HttpResponse.BodyHandlers.ofString());
+            return response.statusCode() == 200;
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
+    private int hardenRoute(String file, String endpoint, String 
resolvedApiKey) throws Exception {
+        Path path = Path.of(file);
+        if (!Files.exists(path)) {
+            printer().printErr("File not found: " + file);
+            return 1;
+        }
+
+        String routeContent = Files.readString(path);
+        String ext = Optional.ofNullable(FileUtil.onlyExt(file, 
false)).orElse("yaml");
+
+        printFileHeader(file);
+
+        String sysPrompt = buildSystemPrompt();
+        String userPrompt = buildUserPrompt(routeContent, ext, file);
+
+        printPromptsIfRequested(sysPrompt, userPrompt);
+
+        String suggestions = apiType.call(this, endpoint, sysPrompt, 
userPrompt, resolvedApiKey);
+
+        return handleHardeningResult(suggestions);
+    }
+
+    private void printFileHeader(String file) {
+        printer().println("=".repeat(70));
+        printer().println("Security Hardening Analysis: " + file);
+        printer().println("=".repeat(70));
+        printer().println();
+    }
+
+    private void printPromptsIfRequested(String sysPrompt, String userPrompt) {
+        if (!showPrompt) {
+            return;
+        }
+        printer().println("--- SYSTEM PROMPT ---");
+        printer().println(sysPrompt);
+        printer().println("--- USER PROMPT ---");
+        printer().println(userPrompt);
+        printer().println("--- END PROMPTS ---");
+        printer().println();
+    }
+
+    private int handleHardeningResult(String suggestions) {
+        if (suggestions == null) {
+            printer().printErr("Failed to get security hardening suggestions 
from LLM");
+            return 1;
+        }
+        // With streaming, response was already printed during generation
+        // Without streaming, we need to print it now
+        if (!stream) {
+            printer().println(suggestions);
+        }
+        printer().println();
+        return 0;
+    }
+
+    private String buildSystemPrompt() {
+        if (systemPrompt != null && !systemPrompt.isBlank()) {
+            return systemPrompt;
+        }
+
+        StringBuilder prompt = new StringBuilder();
+        prompt.append("You are an Apache Camel security expert specializing in 
integration security. ");
+        prompt.append("Your task is to analyze Camel routes and provide 
security hardening recommendations.\n\n");
+
+        prompt.append("Focus on these security areas:\n");
+        prompt.append("1. AUTHENTICATION & AUTHORIZATION\n");
+        prompt.append("   - Missing or weak authentication mechanisms\n");
+        prompt.append("   - Lack of authorization checks\n");
+        prompt.append("   - API key and credential exposure\n\n");
+
+        prompt.append("2. ENCRYPTION & DATA PROTECTION\n");
+        prompt.append("   - Data in transit (TLS/SSL configuration)\n");
+        prompt.append("   - Data at rest encryption\n");
+        prompt.append("   - Certificate validation\n\n");
+
+        prompt.append("3. SECRETS MANAGEMENT\n");
+        prompt.append("   - Hardcoded credentials or secrets\n");
+        prompt.append("   - Secrets in configuration files\n");
+        prompt.append("   - Recommend vault integration (HashiCorp Vault, AWS 
Secrets Manager, etc.)\n\n");
+
+        prompt.append("4. INPUT VALIDATION & INJECTION PREVENTION\n");
+        prompt.append("   - SQL injection vulnerabilities\n");
+        prompt.append("   - Command injection risks\n");
+        prompt.append("   - XML/JSON injection\n");
+        prompt.append("   - Path traversal vulnerabilities\n\n");
+
+        prompt.append("5. SECURE COMPONENT CONFIGURATION\n");
+        prompt.append("   - Insecure default settings\n");
+        prompt.append("   - Missing security headers\n");
+        prompt.append("   - Overly permissive configurations\n\n");
+
+        prompt.append("6. LOGGING & MONITORING\n");
+        prompt.append("   - Sensitive data in logs\n");
+        prompt.append("   - Missing audit trails\n");
+        prompt.append("   - Security event monitoring\n\n");
+
+        prompt.append("Guidelines:\n");
+        prompt.append("- Start with an executive summary of the security 
posture\n");
+        prompt.append("- Prioritize findings by severity: Critical, High, 
Medium, Low\n");
+        prompt.append("- For each finding, explain the risk and provide a 
specific remediation\n");
+        prompt.append("- Reference OWASP guidelines where applicable\n");
+
+        if ("markdown".equals(format)) {
+            prompt.append("- Format output as Markdown with clear sections and 
code blocks\n");
+        }
+        if (verbose) {
+            prompt.append("- Include specific code examples showing secure 
implementations\n");
+            prompt.append("- Provide configuration snippets for recommended 
security settings\n");
+        }
+
+        return prompt.toString();
+    }
+
+    private String buildUserPrompt(String routeContent, String fileExtension, 
String fileName) {
+        StringBuilder prompt = new StringBuilder();
+
+        if (catalogContext) {
+            appendCatalogContext(prompt, routeContent);
+        }
+
+        prompt.append("File: ").append(fileName).append("\n");
+        prompt.append("Format: 
").append(fileExtension.toUpperCase()).append("\n\n");
+        prompt.append("Route 
definition:\n```").append(fileExtension).append("\n");
+        prompt.append(routeContent).append("\n```\n\n");
+        prompt.append("Please perform a security analysis of this Camel route 
and provide hardening recommendations:");
+
+        return prompt.toString();
+    }
+
+    private void appendCatalogContext(StringBuilder prompt, String 
routeContent) {
+        String catalogInfo = buildCatalogContext(routeContent);
+        if (catalogInfo.isEmpty()) {
+            return;
+        }
+        prompt.append("Security-relevant component 
information:\n").append(catalogInfo).append("\n");
+    }
+
+    private String buildCatalogContext(String routeContent) {
+        StringBuilder context = new StringBuilder();
+        CamelCatalog catalog = new DefaultCamelCatalog();
+        String lowerContent = routeContent.toLowerCase();
+
+        SECURITY_SENSITIVE_COMPONENTS.stream()
+                .filter(comp -> containsComponent(lowerContent, comp))
+                .forEach(comp -> {
+                    ComponentModel model = catalog.componentModel(comp);
+                    if (model != null) {
+                        context.append("- ").append(comp).append(": 
").append(model.getDescription());
+                        String securityNote = getSecurityNote(comp);
+                        if (securityNote != null) {
+                            context.append(" [Security: 
").append(securityNote).append("]");
+                        }
+                        context.append("\n");
+                    }
+                });
+
+        return context.toString();
+    }
+
+    private String getSecurityNote(String component) {
+        return switch (component) {
+            case "http" -> "Prefer HTTPS; validate certificates; configure 
timeouts";
+            case "https" -> "Verify TLS version >= 1.2; validate certificates";
+            case "kafka" -> "Enable SASL authentication; use SSL; configure 
ACLs";
+            case "sql", "jdbc" -> "Use parameterized queries to prevent SQL 
injection";
+            case "file" -> "Validate file paths; prevent path traversal";
+            case "ftp" -> "Prefer SFTP/FTPS over plain FTP";
+            case "exec" -> "High risk - validate all inputs to prevent command 
injection";
+            case "ssh" -> "Use key-based authentication; validate host keys";
+            case "rest", "rest-api", "platform-http" ->
+                "Implement authentication; validate input; set security 
headers";
+            case "ldap" -> "Use LDAPS; prevent LDAP injection";
+            case "mongodb", "redis" -> "Enable authentication; use TLS";
+            case "jms", "activemq", "amqp" -> "Enable authentication; use 
SSL/TLS";
+            case "aws2-s3", "aws2-sqs", "aws2-sns" -> "Use IAM roles; enable 
server-side encryption";
+            case "azure-storage-blob" -> "Use managed identities; enable 
encryption";
+            case "smtp", "imap" -> "Use TLS (SMTPS/IMAPS); authenticate 
securely";
+            default -> null;
+        };
+    }
+
+    private boolean containsComponent(String content, String comp) {
+        return content.contains(comp + ":")
+                || content.contains("\"" + comp + "\"")
+                || content.contains("'" + comp + "'");
+    }
+
+    String callOllama(String endpoint, String sysPrompt, String userPrompt) {
+        JsonObject request = new JsonObject();
+        request.put("model", model);
+        request.put("prompt", userPrompt);
+        request.put("system", sysPrompt);
+        request.put("stream", stream);
+
+        JsonObject options = new JsonObject();
+        options.put("temperature", temperature);
+        request.put("options", options);
+
+        printer().println("Performing security analysis with " + model + " 
(Ollama)...");
+        printer().println();
+
+        if (stream) {
+            return sendStreamingRequest(endpoint + "/api/generate", request);
+        }
+        JsonObject response = sendRequest(endpoint + "/api/generate", request, 
null);
+        return response != null ? response.getString("response") : null;
+    }
+
+    String callOpenAiCompatible(String endpoint, String sysPrompt, String 
userPrompt, String resolvedApiKey) {
+        JsonArray messages = new JsonArray();
+        messages.add(createMessage("system", sysPrompt));
+        messages.add(createMessage("user", userPrompt));
+
+        JsonObject request = new JsonObject();
+        request.put("model", model);
+        request.put("messages", messages);
+        request.put("temperature", temperature);
+
+        String apiUrl = normalizeOpenAiUrl(endpoint);
+
+        printer().println("Performing security analysis with " + model + " 
(OpenAI-compatible)...");
+        printer().println();
+
+        JsonObject response = sendRequest(apiUrl, request, resolvedApiKey);
+        return extractOpenAiContent(response);
+    }
+
+    private JsonObject createMessage(String role, String content) {
+        JsonObject msg = new JsonObject();
+        msg.put("role", role);
+        msg.put("content", content);
+        return msg;
+    }
+
+    private String normalizeOpenAiUrl(String endpoint) {
+        String normalizedUrl = endpoint.endsWith("/") ? endpoint.substring(0, 
endpoint.length() - 1) : endpoint;
+        if (!normalizedUrl.endsWith("/v1/chat/completions")) {
+            normalizedUrl = normalizedUrl.endsWith("/v1") ? normalizedUrl : 
normalizedUrl + "/v1";
+            normalizedUrl = normalizedUrl + "/chat/completions";
+        }
+        return normalizedUrl;
+    }
+
+    private String extractOpenAiContent(JsonObject response) {
+        if (response == null) {
+            return null;
+        }
+        JsonArray choices = (JsonArray) response.get("choices");
+        if (choices == null || choices.isEmpty()) {
+            return null;
+        }
+        JsonObject firstChoice = (JsonObject) choices.get(0);
+        JsonObject message = (JsonObject) firstChoice.get("message");
+        return message != null ? message.getString("content") : null;
+    }
+
+    private String sendStreamingRequest(String requestUrl, JsonObject body) {
+        try {
+            HttpRequest request = HttpRequest.newBuilder()
+                    .uri(URI.create(requestUrl))
+                    .timeout(Duration.ofSeconds(timeout))
+                    .header("Content-Type", "application/json")
+                    .POST(HttpRequest.BodyPublishers.ofString(body.toJson()))
+                    .build();
+
+            HttpResponse<Stream<String>> response = httpClient.send(
+                    request, HttpResponse.BodyHandlers.ofLines());
+
+            if (response.statusCode() != 200) {
+                handleErrorStatus(response.statusCode(), "Streaming request 
failed");
+                return null;
+            }
+
+            StringBuilder fullResponse = new StringBuilder();
+            response.body().forEach(line -> {
+                if (line.isBlank()) {
+                    return;
+                }
+                try {
+                    JsonObject chunk = (JsonObject) Jsoner.deserialize(line);
+                    String text = chunk.getString("response");
+                    if (text != null) {
+                        printer().print(text);
+                        fullResponse.append(text);
+                    }
+                } catch (Exception e) {
+                    // Skip malformed chunks
+                }
+            });
+
+            printer().println();
+            return fullResponse.toString();
+
+        } catch (java.net.http.HttpTimeoutException e) {
+            printer().printErr("\nRequest timed out after " + timeout + " 
seconds.");
+            return null;
+        } catch (Exception e) {
+            printer().printErr("\nError during streaming: " + e.getMessage());
+            return null;
+        }
+    }
+
+    private JsonObject sendRequest(String requestUrl, JsonObject body, String 
authKey) {
+        try {
+            HttpRequest.Builder builder = HttpRequest.newBuilder()
+                    .uri(URI.create(requestUrl))
+                    .timeout(Duration.ofSeconds(timeout))
+                    .header("Content-Type", "application/json")
+                    .POST(HttpRequest.BodyPublishers.ofString(body.toJson()));
+
+            if (authKey != null && !authKey.isBlank()) {
+                builder.header("Authorization", "Bearer " + authKey);
+            }
+
+            HttpResponse<String> response = httpClient.send(builder.build(), 
HttpResponse.BodyHandlers.ofString());
+
+            if (response.statusCode() == 200) {
+                return (JsonObject) Jsoner.deserialize(response.body());
+            }
+
+            handleErrorStatus(response.statusCode(), response.body());
+            return null;
+
+        } catch (java.net.http.HttpTimeoutException e) {
+            printer().printErr("Request timed out after " + timeout + " 
seconds.");
+            return null;
+        } catch (Exception e) {
+            printer().printErr("Error calling LLM: " + e.getMessage());
+            return null;
+        }
+    }
+
+    private void handleErrorStatus(int statusCode, String body) {
+        printer().printErr("LLM returned status: " + statusCode);
+        switch (statusCode) {
+            case 401 -> printer().printErr("Authentication failed. Check your 
API key.");
+            case 404 -> printer().printErr("Model '" + model + "' not found.");
+            case 429 -> printer().printErr("Rate limit exceeded.");
+            default -> printer().printErr(body);
+        }
+    }
+}
diff --git 
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/HardenTools.java
 
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/HardenTools.java
new file mode 100644
index 000000000000..8832fd3c336a
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/HardenTools.java
@@ -0,0 +1,452 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.dsl.jbang.core.commands.mcp;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import jakarta.enterprise.context.ApplicationScoped;
+
+import io.quarkiverse.mcp.server.Tool;
+import io.quarkiverse.mcp.server.ToolArg;
+import io.quarkiverse.mcp.server.ToolCallException;
+import org.apache.camel.catalog.CamelCatalog;
+import org.apache.camel.catalog.DefaultCamelCatalog;
+import org.apache.camel.tooling.model.ComponentModel;
+import org.apache.camel.util.json.JsonArray;
+import org.apache.camel.util.json.JsonObject;
+
+/**
+ * MCP Tool for providing security hardening context and analysis for Camel 
routes.
+ * <p>
+ * This tool analyzes routes for security-sensitive components, identifies 
potential vulnerabilities, and provides
+ * structured context that an LLM can use to formulate security hardening 
recommendations.
+ */
+@ApplicationScoped
+public class HardenTools {
+
+    // Components with significant security considerations
+    private static final List<String> SECURITY_SENSITIVE_COMPONENTS = 
Arrays.asList(
+            // Network/API components - need TLS, authentication
+            "http", "https", "netty-http", "vertx-http", "websocket",
+            "rest", "rest-api", "platform-http", "servlet", "undertow", 
"jetty",
+            // Messaging - need authentication, encryption
+            "kafka", "jms", "activemq", "amqp", "rabbitmq", "pulsar",
+            "aws2-sqs", "aws2-sns", "aws2-kinesis",
+            "azure-servicebus", "azure-eventhubs",
+            "google-pubsub",
+            // File/Storage - need access control, path validation
+            "file", "ftp", "sftp", "ftps",
+            "aws2-s3", "azure-storage-blob", "azure-storage-queue", 
"azure-files",
+            "google-storage", "minio",
+            // Database - need authentication, SQL injection prevention
+            "sql", "jdbc", "mongodb", "couchdb", "cassandraql",
+            "elasticsearch", "opensearch", "redis",
+            // Email - need authentication, TLS
+            "smtp", "smtps", "imap", "imaps", "pop3", "pop3s",
+            // Remote execution - high risk, need strict validation
+            "exec", "ssh", "docker",
+            // Directory services - need secure binding
+            "ldap", "ldaps",
+            // Secrets management
+            "hashicorp-vault", "aws2-secrets-manager", "azure-key-vault", 
"google-secret-manager");
+
+    private static final List<String> SECURITY_BEST_PRACTICES = Arrays.asList(
+            "Use TLS/SSL (version 1.2+) for all network communications",
+            "Store secrets in vault services (HashiCorp Vault, AWS Secrets 
Manager, Azure Key Vault, etc.)",
+            "Use property placeholders for sensitive configuration values",
+            "Enable authentication for all endpoints and services",
+            "Validate and sanitize all input data to prevent injection 
attacks",
+            "Use parameterized queries for database operations",
+            "Implement proper certificate validation - do not disable SSL 
verification",
+            "Use principle of least privilege for service accounts and IAM 
roles",
+            "Enable audit logging for sensitive operations",
+            "Implement proper error handling without exposing internal 
details",
+            "Use HTTPS instead of HTTP for all external communications",
+            "Configure appropriate timeouts to prevent resource exhaustion",
+            "Validate file paths to prevent path traversal attacks",
+            "Use SFTP/FTPS instead of plain FTP");
+
+    private final CamelCatalog catalog;
+
+    public HardenTools() {
+        this.catalog = new DefaultCamelCatalog();
+    }
+
+    /**
+     * Tool to get security hardening context for a Camel route.
+     */
+    @Tool(description = "Get security hardening analysis context for a Camel 
route. " +
+                        "Returns security-sensitive components, potential 
vulnerabilities, " +
+                        "and security best practices. Use this context to 
provide security " +
+                        "hardening recommendations for the route.")
+    public String camel_route_harden_context(
+            @ToolArg(description = "The Camel route content (YAML, XML, or 
Java DSL)") String route,
+            @ToolArg(description = "Route format: yaml, xml, or java (default: 
yaml)") String format) {
+
+        if (route == null || route.isBlank()) {
+            throw new ToolCallException("Route content is required", null);
+        }
+
+        String resolvedFormat = format != null && !format.isBlank() ? 
format.toLowerCase() : "yaml";
+
+        JsonObject result = new JsonObject();
+        result.put("format", resolvedFormat);
+        result.put("route", route);
+
+        // Analyze security-sensitive components
+        List<String> securityComponents = extractSecurityComponents(route);
+        JsonArray securityComponentsJson = new JsonArray();
+        for (String comp : securityComponents) {
+            ComponentModel model = catalog.componentModel(comp);
+            if (model != null) {
+                JsonObject compJson = new JsonObject();
+                compJson.put("name", comp);
+                compJson.put("title", model.getTitle());
+                compJson.put("description", model.getDescription());
+                compJson.put("label", model.getLabel());
+                compJson.put("securityConsiderations", 
getSecurityConsiderations(comp));
+                compJson.put("riskLevel", getRiskLevel(comp));
+                securityComponentsJson.add(compJson);
+            }
+        }
+        result.put("securitySensitiveComponents", securityComponentsJson);
+
+        // Security analysis
+        JsonObject securityAnalysis = analyzeSecurityConcerns(route);
+        result.put("securityAnalysis", securityAnalysis);
+
+        // Best practices
+        JsonArray bestPractices = new JsonArray();
+        for (String practice : SECURITY_BEST_PRACTICES) {
+            bestPractices.add(practice);
+        }
+        result.put("securityBestPractices", bestPractices);
+
+        // Summary
+        JsonObject summary = new JsonObject();
+        summary.put("securityComponentCount", securityComponentsJson.size());
+        summary.put("criticalRiskComponents", 
countComponentsByRisk(securityComponents, "critical"));
+        summary.put("highRiskComponents", 
countComponentsByRisk(securityComponents, "high"));
+        summary.put("concernCount", 
securityAnalysis.getInteger("concernCount"));
+        summary.put("positiveCount", 
securityAnalysis.getInteger("positiveCount"));
+        summary.put("hasExternalConnections", hasExternalConnections(route));
+        summary.put("hasSecretsManagement", hasSecretsManagement(route));
+        summary.put("usesTLS", usesTLS(route));
+        summary.put("hasAuthentication", hasAuthentication(route));
+        result.put("summary", summary);
+
+        return result.toJson();
+    }
+
+    /**
+     * Extract security-sensitive components from route content.
+     */
+    private List<String> extractSecurityComponents(String route) {
+        List<String> found = new ArrayList<>();
+        String lowerRoute = route.toLowerCase();
+
+        for (String comp : SECURITY_SENSITIVE_COMPONENTS) {
+            if (containsComponent(lowerRoute, comp)) {
+                found.add(comp);
+            }
+        }
+
+        return found;
+    }
+
+    /**
+     * Analyze security concerns in the route.
+     */
+    private JsonObject analyzeSecurityConcerns(String route) {
+        JsonObject analysis = new JsonObject();
+        JsonArray concerns = new JsonArray();
+        JsonArray positives = new JsonArray();
+        String lowerRoute = route.toLowerCase();
+
+        // Check for hardcoded credentials
+        if (containsHardcodedCredentials(lowerRoute)) {
+            JsonObject concern = new JsonObject();
+            concern.put("severity", "critical");
+            concern.put("category", "Secrets Management");
+            concern.put("issue", "Potential hardcoded credentials detected");
+            concern.put("recommendation", "Use property placeholders 
{{secret}} or vault services for credentials");
+            concerns.add(concern);
+        }
+
+        // Check for HTTP instead of HTTPS
+        if (lowerRoute.contains("http:") && !lowerRoute.contains("https:")) {
+            JsonObject concern = new JsonObject();
+            concern.put("severity", "high");
+            concern.put("category", "Encryption");
+            concern.put("issue", "Using HTTP instead of HTTPS");
+            concern.put("recommendation", "Use HTTPS for secure communication. 
Configure TLS version 1.2 or higher");
+            concerns.add(concern);
+        }
+
+        // Check for plain FTP
+        if (lowerRoute.contains("ftp:") && !lowerRoute.contains("sftp:") && 
!lowerRoute.contains("ftps:")) {
+            JsonObject concern = new JsonObject();
+            concern.put("severity", "high");
+            concern.put("category", "Encryption");
+            concern.put("issue", "Using plain FTP instead of SFTP/FTPS");
+            concern.put("recommendation", "Use SFTP or FTPS for encrypted file 
transfers");
+            concerns.add(concern);
+        }
+
+        // Check for SSL/TLS disabled
+        if (lowerRoute.contains("sslcontextparameters") && 
lowerRoute.contains("false")) {
+            JsonObject concern = new JsonObject();
+            concern.put("severity", "critical");
+            concern.put("category", "Encryption");
+            concern.put("issue", "SSL/TLS may be disabled or misconfigured");
+            concern.put("recommendation", "Ensure SSL/TLS is properly enabled 
and configured");
+            concerns.add(concern);
+        }
+
+        // Check for exec component (high risk)
+        if (lowerRoute.contains("exec:")) {
+            JsonObject concern = new JsonObject();
+            concern.put("severity", "critical");
+            concern.put("category", "Command Injection");
+            concern.put("issue", "Using exec component - high risk for command 
injection");
+            concern.put("recommendation",
+                    "Validate all inputs strictly. Consider if exec is really 
necessary or if safer alternatives exist");
+            concerns.add(concern);
+        }
+
+        // Check for SQL without parameterized queries indicator
+        if (lowerRoute.contains("sql:") && !lowerRoute.contains(":#") && 
!lowerRoute.contains(":?")) {
+            JsonObject concern = new JsonObject();
+            concern.put("severity", "high");
+            concern.put("category", "SQL Injection");
+            concern.put("issue", "SQL query may not use parameterized 
queries");
+            concern.put("recommendation", "Use parameterized queries with 
named parameters (:#param) or positional (:?)");
+            concerns.add(concern);
+        }
+
+        // Check for LDAP injection risk
+        if (lowerRoute.contains("ldap:") && !lowerRoute.contains("ldaps:")) {
+            JsonObject concern = new JsonObject();
+            concern.put("severity", "medium");
+            concern.put("category", "Encryption");
+            concern.put("issue", "Using LDAP instead of LDAPS");
+            concern.put("recommendation", "Use LDAPS for encrypted LDAP 
communication");
+            concerns.add(concern);
+        }
+
+        // Check for file component path validation
+        if (lowerRoute.contains("file:") && lowerRoute.contains("${")) {
+            JsonObject concern = new JsonObject();
+            concern.put("severity", "medium");
+            concern.put("category", "Path Traversal");
+            concern.put("issue", "File path contains dynamic expression - 
potential path traversal risk");
+            concern.put("recommendation", "Validate file paths and restrict to 
allowed directories");
+            concerns.add(concern);
+        }
+
+        // POSITIVE CHECKS
+
+        // Check for TLS/SSL usage
+        if (usesTLS(lowerRoute)) {
+            JsonObject positive = new JsonObject();
+            positive.put("category", "Encryption");
+            positive.put("finding", "TLS/SSL encryption is configured");
+            positives.add(positive);
+        }
+
+        // Check for property placeholders (good practice)
+        if (lowerRoute.contains("{{") && lowerRoute.contains("}}")) {
+            JsonObject positive = new JsonObject();
+            positive.put("category", "Secrets Management");
+            positive.put("finding", "Using property placeholders for 
configuration");
+            positives.add(positive);
+        }
+
+        // Check for vault integration
+        if (hasSecretsManagement(lowerRoute)) {
+            JsonObject positive = new JsonObject();
+            positive.put("category", "Secrets Management");
+            positive.put("finding", "Integrated with secrets management 
service");
+            positives.add(positive);
+        }
+
+        // Check for authentication configuration
+        if (hasAuthentication(lowerRoute)) {
+            JsonObject positive = new JsonObject();
+            positive.put("category", "Authentication");
+            positive.put("finding", "Authentication appears to be configured");
+            positives.add(positive);
+        }
+
+        // Check for HTTPS usage
+        if (lowerRoute.contains("https:")) {
+            JsonObject positive = new JsonObject();
+            positive.put("category", "Encryption");
+            positive.put("finding", "Using HTTPS for secure HTTP 
communication");
+            positives.add(positive);
+        }
+
+        // Check for SFTP/FTPS usage
+        if (lowerRoute.contains("sftp:") || lowerRoute.contains("ftps:")) {
+            JsonObject positive = new JsonObject();
+            positive.put("category", "Encryption");
+            positive.put("finding", "Using secure file transfer protocol 
(SFTP/FTPS)");
+            positives.add(positive);
+        }
+
+        analysis.put("concerns", concerns);
+        analysis.put("positives", positives);
+        analysis.put("concernCount", concerns.size());
+        analysis.put("positiveCount", positives.size());
+
+        return analysis;
+    }
+
+    /**
+     * Get security considerations for a specific component.
+     */
+    private String getSecurityConsiderations(String component) {
+        return switch (component) {
+            case "http" ->
+                "Prefer HTTPS over HTTP. Validate certificates. Configure 
appropriate timeouts. Set security headers.";
+            case "https" ->
+                "Verify TLS version is 1.2 or higher. Enable certificate 
validation. Configure secure cipher suites.";
+            case "kafka" ->
+                "Enable SASL authentication (SCRAM-SHA-256/512 or GSSAPI). Use 
SSL for encryption. Configure ACLs for authorization.";
+            case "sql", "jdbc" ->
+                "Use parameterized queries to prevent SQL injection. Limit 
database user privileges. Enable connection encryption.";
+            case "file" ->
+                "Validate file paths to prevent traversal attacks. Restrict 
directory access. Set appropriate file permissions.";
+            case "ftp" ->
+                "INSECURE: Use SFTP or FTPS instead. Plain FTP transmits 
credentials in cleartext.";
+            case "sftp" ->
+                "Use key-based authentication. Validate host keys. Configure 
known_hosts file.";
+            case "ftps" ->
+                "Enable explicit FTPS. Verify server certificates. Use strong 
TLS version.";
+            case "exec" ->
+                "HIGH RISK: Validate and sanitize all inputs to prevent 
command injection. Consider safer alternatives.";
+            case "ssh" ->
+                "Use key-based authentication. Validate host keys. Disable 
password authentication if possible.";
+            case "rest", "rest-api", "platform-http" ->
+                "Implement authentication (OAuth2, JWT, API keys). Validate 
all input. Set CORS policies. Add security headers.";
+            case "ldap" ->
+                "Use LDAPS for encryption. Escape special characters to 
prevent LDAP injection. Use service account with minimal privileges.";
+            case "ldaps" ->
+                "Verify server certificates. Use strong TLS. Escape special 
characters in queries.";
+            case "mongodb" ->
+                "Enable authentication. Use TLS for connections. Limit network 
exposure. Use SCRAM authentication.";
+            case "redis" ->
+                "Enable authentication (requirepass or ACL). Use TLS. Limit 
network exposure. Disable dangerous commands.";
+            case "jms", "activemq", "amqp", "rabbitmq" ->
+                "Enable authentication. Use SSL/TLS for connections. Configure 
authorization policies.";
+            case "aws2-s3", "aws2-sqs", "aws2-sns", "aws2-kinesis" ->
+                "Use IAM roles instead of access keys. Enable server-side 
encryption. Configure bucket/queue policies.";
+            case "aws2-secrets-manager" ->
+                "Use IAM roles for access. Enable automatic rotation. Audit 
secret access.";
+            case "azure-storage-blob", "azure-storage-queue", "azure-files" ->
+                "Use managed identities. Enable encryption at rest. Configure 
access policies.";
+            case "azure-key-vault" ->
+                "Use managed identities. Enable soft-delete. Configure access 
policies and RBAC.";
+            case "google-storage", "google-pubsub" ->
+                "Use service accounts with minimal permissions. Enable 
encryption. Configure IAM policies.";
+            case "google-secret-manager" ->
+                "Use service accounts. Enable automatic rotation. Audit 
access.";
+            case "hashicorp-vault" ->
+                "Use AppRole or Kubernetes auth. Configure token TTLs. Enable 
audit logging.";
+            case "elasticsearch", "opensearch" ->
+                "Enable authentication. Use TLS. Configure role-based access 
control.";
+            case "smtp", "smtps", "imap", "imaps", "pop3", "pop3s" ->
+                "Use TLS variants (SMTPS, IMAPS, POP3S). Use secure 
authentication. Store credentials securely.";
+            case "websocket" ->
+                "Use WSS (WebSocket Secure). Implement authentication. 
Validate origin headers.";
+            case "docker" ->
+                "HIGH RISK: Validate all inputs. Use least privilege. Consider 
container security policies.";
+            case "netty-http", "vertx-http", "undertow", "jetty", "servlet" ->
+                "Enable TLS. Implement authentication. Set security headers. 
Validate input.";
+            case "pulsar" ->
+                "Enable TLS encryption. Configure authentication (JWT, 
Athenz). Set authorization policies.";
+            case "minio" ->
+                "Enable TLS. Use access/secret keys securely. Configure bucket 
policies.";
+            case "couchdb", "cassandraql" ->
+                "Enable authentication. Use TLS for connections. Configure 
role-based access.";
+            default -> "Review security configuration for this component";
+        };
+    }
+
+    /**
+     * Get risk level for a component.
+     */
+    private String getRiskLevel(String component) {
+        return switch (component) {
+            case "exec", "docker" -> "critical";
+            case "http", "ftp", "ldap", "sql", "jdbc" -> "high";
+            case "file", "ssh", "rest", "rest-api", "platform-http", "kafka", 
"mongodb", "redis" -> "medium";
+            default -> "low";
+        };
+    }
+
+    private int countComponentsByRisk(List<String> components, String 
riskLevel) {
+        return (int) components.stream()
+                .filter(c -> riskLevel.equals(getRiskLevel(c)))
+                .count();
+    }
+
+    private boolean containsHardcodedCredentials(String route) {
+        return (route.contains("password=") || route.contains("password:"))
+                && !route.contains("{{") && !route.contains("$");
+    }
+
+    private boolean containsComponent(String content, String comp) {
+        return content.contains(comp + ":")
+                || content.contains("\"" + comp + "\"")
+                || content.contains("'" + comp + "'");
+    }
+
+    private boolean hasExternalConnections(String route) {
+        String lowerRoute = route.toLowerCase();
+        return lowerRoute.contains("http:") || lowerRoute.contains("https:")
+                || lowerRoute.contains("kafka:") || lowerRoute.contains("jms:")
+                || lowerRoute.contains("sql:") || 
lowerRoute.contains("mongodb:")
+                || lowerRoute.contains("aws2-") || 
lowerRoute.contains("azure-");
+    }
+
+    private boolean hasSecretsManagement(String route) {
+        String lowerRoute = route.toLowerCase();
+        return lowerRoute.contains("hashicorp-vault") || 
lowerRoute.contains("aws-secrets-manager")
+                || lowerRoute.contains("aws2-secrets-manager")
+                || lowerRoute.contains("azure-key-vault") || 
lowerRoute.contains("google-secret-manager");
+    }
+
+    private boolean usesTLS(String route) {
+        String lowerRoute = route.toLowerCase();
+        return lowerRoute.contains("ssl=true") || 
lowerRoute.contains("usessl=true")
+                || lowerRoute.contains("https:") || 
lowerRoute.contains("sftp:")
+                || lowerRoute.contains("ftps:") || 
lowerRoute.contains("ldaps:")
+                || lowerRoute.contains("smtps:") || 
lowerRoute.contains("imaps:")
+                || lowerRoute.contains("sslcontextparameters");
+    }
+
+    private boolean hasAuthentication(String route) {
+        String lowerRoute = route.toLowerCase();
+        return lowerRoute.contains("username=") || 
lowerRoute.contains("authmethod=")
+                || lowerRoute.contains("saslmechanism=") || 
lowerRoute.contains("oauth")
+                || lowerRoute.contains("bearer") || 
lowerRoute.contains("apikey")
+                || lowerRoute.contains("securityprovider");
+    }
+}
diff --git 
a/dsl/camel-jbang/camel-jbang-mcp/src/main/resources/application.properties 
b/dsl/camel-jbang/camel-jbang-mcp/src/main/resources/application.properties
index 16a9e79de4f8..bc542097a290 100644
--- a/dsl/camel-jbang/camel-jbang-mcp/src/main/resources/application.properties
+++ b/dsl/camel-jbang/camel-jbang-mcp/src/main/resources/application.properties
@@ -29,3 +29,6 @@ quarkus.log.console.stderr=true
 quarkus.log.level=WARN
 quarkus.log.category."org.apache.camel".level=INFO
 quarkus.log.category."io.quarkiverse.mcp".level=INFO
+
+# Disable HTTP server - use STDIO transport only for CLI integration
+quarkus.http.host-enabled=false

Reply via email to