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

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

commit 33b30df35ad3b9c80b75fec534dbb361a237d411
Author: Croway <[email protected]>
AuthorDate: Mon Feb 16 18:16:52 2026 +0100

    (feat): Camel MCP - Migration/Upgrades tools
---
 dsl/camel-jbang/camel-jbang-mcp/pom.xml            |  60 +++
 .../dsl/jbang/core/commands/mcp/MigrationData.java | 553 +++++++++++++++++++++
 .../core/commands/mcp/MigrationResources.java      | 102 ++++
 .../jbang/core/commands/mcp/MigrationTools.java    | 395 +++++++++++++++
 .../commands/mcp/MigrationWildflyKarafTools.java   | 179 +++++++
 .../core/commands/mcp/MigrationDataSearchTest.java |  64 +++
 6 files changed, 1353 insertions(+)

diff --git a/dsl/camel-jbang/camel-jbang-mcp/pom.xml 
b/dsl/camel-jbang/camel-jbang-mcp/pom.xml
index be3855f34d2b..629840ad673d 100644
--- a/dsl/camel-jbang/camel-jbang-mcp/pom.xml
+++ b/dsl/camel-jbang/camel-jbang-mcp/pom.xml
@@ -106,6 +106,13 @@
             <artifactId>camel-yaml-dsl</artifactId>
         </dependency>
 
+        <!-- Apache Commons Text for fuzzy string matching (Levenshtein 
distance) -->
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-text</artifactId>
+            <version>${commons-text-version}</version>
+        </dependency>
+
         <!-- test dependencies -->
         <dependency>
             <groupId>io.quarkus</groupId>
@@ -136,6 +143,59 @@
                     </execution>
                 </executions>
             </plugin>
+            <!-- Copy migration guide .adoc files into the uber-JAR for 
runtime search -->
+            <plugin>
+                <artifactId>maven-resources-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>copy-migration-guides</id>
+                        <phase>generate-resources</phase>
+                        <goals>
+                            <goal>copy-resources</goal>
+                        </goals>
+                        <configuration>
+                            
<outputDirectory>${project.build.outputDirectory}/migration-guides</outputDirectory>
+                            <resources>
+                                <resource>
+                                    
<directory>${project.basedir}/../../../docs/user-manual/modules/ROOT/pages</directory>
+                                    <filtering>false</filtering>
+                                    <includes>
+                                        
<include>camel-3-migration-guide.adoc</include>
+                                        
<include>camel-4-migration-guide.adoc</include>
+                                        
<include>camel-3x-upgrade-guide-3_*.adoc</include>
+                                        
<include>camel-4x-upgrade-guide-4_*.adoc</include>
+                                    </includes>
+                                </resource>
+                            </resources>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <!-- Generate index.txt listing all copied migration guide 
filenames -->
+            <plugin>
+                <artifactId>maven-antrun-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>generate-migration-guide-index</id>
+                        <phase>process-resources</phase>
+                        <goals>
+                            <goal>run</goal>
+                        </goals>
+                        <configuration>
+                            <target>
+                                <fileset id="guide-files" 
dir="${project.build.outputDirectory}/migration-guides">
+                                    <include name="*.adoc"/>
+                                </fileset>
+                                <pathconvert property="guide-list" 
refid="guide-files" pathsep="${line.separator}">
+                                    <flattenmapper/>
+                                </pathconvert>
+                                <echo 
file="${project.build.outputDirectory}/migration-guides/index.txt"
+                                      message="${guide-list}"/>
+                            </target>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
             <plugin>
                 <artifactId>maven-compiler-plugin</artifactId>
                 <configuration>
diff --git 
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/MigrationData.java
 
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/MigrationData.java
new file mode 100644
index 000000000000..11ebb293e3eb
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/MigrationData.java
@@ -0,0 +1,553 @@
+/*
+ * 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.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Locale;
+import java.util.stream.Collectors;
+
+import jakarta.enterprise.context.ApplicationScoped;
+
+import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import org.apache.commons.text.similarity.LevenshteinDistance;
+
+/**
+ * Shared holder for migration reference data used by {@link MigrationTools}, 
{@link MigrationWildflyKarafTools}, and
+ * {@link MigrationResources}.
+ * <p>
+ * Contains migration guide metadata, WildFly/Karaf detection markers, and POM 
parsing utilities. Component-level
+ * migration details (renames, discontinued components, API changes) are 
intentionally not included here — the LLM
+ * should consult the migration guides directly for that information.
+ */
+@ApplicationScoped
+public class MigrationData {
+
+    // Migration guides
+
+    private static final List<MigrationGuide> MIGRATION_GUIDES = Arrays.asList(
+            new MigrationGuide(
+                    "migration-and-upgrade",
+                    "Migration and Upgrade",
+                    
"https://camel.apache.org/manual/migration-and-upgrade.html";,
+                    "Overview of Camel migration and upgrade options across 
all versions."),
+            new MigrationGuide(
+                    "camel-3-migration",
+                    "Camel 3 Migration Guide",
+                    
"https://camel.apache.org/manual/camel-3-migration-guide.html";,
+                    "Guide for migrating from Camel 2.x to Camel 3.0."),
+            new MigrationGuide(
+                    "camel-4-migration",
+                    "Camel 4 Migration Guide",
+                    
"https://camel.apache.org/manual/camel-4-migration-guide.html";,
+                    "Guide for migrating from Camel 3.x to Camel 4.0."),
+            new MigrationGuide(
+                    "camel-3x-upgrade",
+                    "Camel 3.x Upgrade Guide",
+                    
"https://camel.apache.org/manual/camel-3x-upgrade-guide.html";,
+                    "Detailed upgrade notes for Camel 3.x minor version 
upgrades."),
+            new MigrationGuide(
+                    "camel-4x-upgrade",
+                    "Camel 4.x Upgrade Guide",
+                    
"https://camel.apache.org/manual/camel-4x-upgrade-guide.html";,
+                    "Detailed upgrade notes for Camel 4.x minor version 
upgrades."));
+
+    // WildFly/Karaf detection markers
+
+    private static final List<String> WILDFLY_MARKERS = Arrays.asList(
+            "org.wildfly.camel", "org.wildfly",
+            "org.wildfly.plugins",
+            "javax.ejb", "jakarta.ejb",
+            "camel-cdi", "maven-war-plugin");
+
+    private static final List<String> KARAF_MARKERS = Arrays.asList(
+            "org.apache.karaf", "camel-blueprint",
+            "org.ops4j.pax", "camel-core-osgi",
+            "maven-bundle-plugin");
+
+    // Accessors
+
+    public List<MigrationGuide> getMigrationGuides() {
+        return MIGRATION_GUIDES;
+    }
+
+    public MigrationGuide getMigrationGuide(String name) {
+        return MIGRATION_GUIDES.stream()
+                .filter(g -> g.name().equals(name))
+                .findFirst()
+                .orElse(null);
+    }
+
+    public List<String> getWildflyMarkers() {
+        return WILDFLY_MARKERS;
+    }
+
+    public List<String> getKarafMarkers() {
+        return KARAF_MARKERS;
+    }
+
+    /**
+     * Get relevant migration guides based on the detected Camel major version.
+     */
+    public List<MigrationGuide> getGuidesForVersion(int majorVersion) {
+        List<MigrationGuide> guides = new ArrayList<>();
+        guides.add(getMigrationGuide("migration-and-upgrade"));
+        if (majorVersion <= 2) {
+            guides.add(getMigrationGuide("camel-3-migration"));
+            guides.add(getMigrationGuide("camel-4-migration"));
+        } else if (majorVersion == 3) {
+            guides.add(getMigrationGuide("camel-3x-upgrade"));
+            guides.add(getMigrationGuide("camel-4-migration"));
+        } else {
+            guides.add(getMigrationGuide("camel-4x-upgrade"));
+        }
+        return guides;
+    }
+
+    // POM parsing
+
+    /**
+     * Parse pom.xml content and extract project analysis data.
+     */
+    public static PomAnalysis parsePomContent(String pomContent) throws 
Exception {
+        DocumentBuilderFactory factory = createSecureDocumentBuilderFactory();
+        Document doc = factory.newDocumentBuilder()
+                .parse(new 
ByteArrayInputStream(pomContent.getBytes(StandardCharsets.UTF_8)));
+
+        String camelVersion = null;
+        String springBootVersion = null;
+        String quarkusVersion = null;
+        String javaVersion = null;
+        boolean isWildfly = false;
+        boolean isKaraf = false;
+        List<String> dependencies = new ArrayList<>();
+
+        // Detect packaging type (war packaging is a strong WildFly/app-server 
signal)
+        String packaging = getElementText(doc.getDocumentElement(), 
"packaging");
+        if ("war".equalsIgnoreCase(packaging)) {
+            isWildfly = true;
+        }
+
+        // Extract properties
+        NodeList propertiesNodes = doc.getElementsByTagName("properties");
+        if (propertiesNodes.getLength() > 0) {
+            Element properties = (Element) propertiesNodes.item(0);
+            camelVersion = getElementText(properties, "camel.version");
+            if (camelVersion == null) {
+                camelVersion = getElementText(properties, "camel-version");
+            }
+            springBootVersion = getElementText(properties, 
"spring-boot.version");
+            if (springBootVersion == null) {
+                springBootVersion = getElementText(properties, 
"spring-boot-version");
+            }
+            quarkusVersion = getElementText(properties, 
"quarkus.platform.version");
+            if (quarkusVersion == null) {
+                quarkusVersion = getElementText(properties, 
"quarkus-plugin.version");
+            }
+            javaVersion = getElementText(properties, "maven.compiler.release");
+            if (javaVersion == null) {
+                javaVersion = getElementText(properties, 
"maven.compiler.source");
+            }
+            if (javaVersion == null) {
+                javaVersion = getElementText(properties, 
"maven.compiler.target");
+            }
+        }
+
+        // Scan dependencyManagement and dependencies for version and runtime 
detection
+        NodeList allDeps = doc.getElementsByTagName("dependency");
+        for (int i = 0; i < allDeps.getLength(); i++) {
+            Element dep = (Element) allDeps.item(i);
+            String groupId = getElementText(dep, "groupId");
+            String artifactId = getElementText(dep, "artifactId");
+            String version = getElementText(dep, "version");
+
+            if (groupId == null || artifactId == null) {
+                continue;
+            }
+
+            // Detect Camel version from BOM
+            if (camelVersion == null && version != null && 
!version.startsWith("$")) {
+                if ("camel-bom".equals(artifactId) || 
"camel-spring-boot-bom".equals(artifactId)
+                        || "camel-quarkus-bom".equals(artifactId)) {
+                    camelVersion = version;
+                }
+            }
+
+            // Detect Spring Boot
+            if (springBootVersion == null && version != null && 
!version.startsWith("$")) {
+                if ("spring-boot-dependencies".equals(artifactId)
+                        || "spring-boot-starter-parent".equals(artifactId)) {
+                    springBootVersion = version;
+                }
+            }
+
+            // Detect Quarkus
+            if (quarkusVersion == null && version != null && 
!version.startsWith("$")) {
+                if ("quarkus-bom".equals(artifactId)) {
+                    quarkusVersion = version;
+                }
+            }
+
+            // Detect WildFly
+            for (String marker : WILDFLY_MARKERS) {
+                if (groupId.contains(marker) || artifactId.contains(marker)) {
+                    isWildfly = true;
+                }
+            }
+
+            // Detect Karaf
+            for (String marker : KARAF_MARKERS) {
+                if (groupId.contains(marker) || artifactId.contains(marker)) {
+                    isKaraf = true;
+                }
+            }
+
+            // Collect Camel dependencies
+            if (artifactId.startsWith("camel-")) {
+                dependencies.add(artifactId);
+            }
+        }
+
+        return new PomAnalysis(
+                camelVersion, springBootVersion, quarkusVersion, javaVersion,
+                dependencies, isWildfly, isKaraf);
+    }
+
+    // XML helper
+
+    private static DocumentBuilderFactory createSecureDocumentBuilderFactory() 
{
+        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+        factory.setNamespaceAware(true);
+        factory.setIgnoringElementContentWhitespace(true);
+        factory.setIgnoringComments(true);
+        try {
+            factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, 
Boolean.TRUE);
+        } catch (ParserConfigurationException e) {
+            // ignore
+        }
+        try {
+            
factory.setFeature("http://xml.org/sax/features/external-general-entities";, 
false);
+        } catch (ParserConfigurationException e) {
+            // ignore
+        }
+        try {
+            
factory.setFeature("http://xml.org/sax/features/external-parameter-entities";, 
false);
+        } catch (ParserConfigurationException e) {
+            // ignore
+        }
+        return factory;
+    }
+
+    private static String getElementText(Element parent, String tagName) {
+        NodeList nodes = parent.getElementsByTagName(tagName);
+        if (nodes.getLength() > 0) {
+            String text = nodes.item(0).getTextContent();
+            if (text != null && !text.isBlank()) {
+                return text.trim();
+            }
+        }
+        return null;
+    }
+
+    // Guide search
+
+    private static final String GUIDES_RESOURCE_DIR = "migration-guides/";
+    private static final String GUIDES_INDEX_FILE = GUIDES_RESOURCE_DIR + 
"index.txt";
+
+    private volatile List<GuideSection> guideIndex;
+
+    /**
+     * Get the guide index, loading lazily on first access.
+     */
+    public synchronized List<GuideSection> getGuideIndex() {
+        if (guideIndex == null) {
+            guideIndex = loadGuideSections();
+        }
+        return guideIndex;
+    }
+
+    /**
+     * Search migration guides for sections matching the query using fuzzy 
matching.
+     */
+    public List<GuideSection> searchGuides(String query, int maxResults) {
+        List<String> queryTokens = tokenize(query);
+        String lowerQuery = query.toLowerCase(Locale.ROOT);
+
+        List<GuideSection> index = getGuideIndex();
+        List<ScoredSection> scored = new ArrayList<>();
+
+        for (GuideSection section : index) {
+            double score = scoreSection(section, queryTokens, lowerQuery);
+            if (score > 0) {
+                scored.add(new ScoredSection(section, score));
+            }
+        }
+
+        
scored.sort(Comparator.comparingDouble(ScoredSection::score).reversed());
+
+        return scored.stream()
+                .limit(maxResults)
+                .map(ScoredSection::section)
+                .collect(Collectors.toList());
+    }
+
+    private double scoreSection(GuideSection section, List<String> 
queryTokens, String lowerQuery) {
+        double score = 0;
+        String lowerContent = section.content().toLowerCase(Locale.ROOT);
+
+        // Bonus for exact substring match of the full query
+        if (lowerContent.contains(lowerQuery)) {
+            score += 10;
+        }
+
+        // Token-level scoring
+        for (String qt : queryTokens) {
+            boolean exactFound = false;
+            boolean fuzzyFound = false;
+            boolean substringFound = false;
+
+            for (String dt : section.tokens()) {
+                if (dt.equals(qt)) {
+                    exactFound = true;
+                    break;
+                }
+                int maxDist = Math.max(1, Math.min(qt.length(), dt.length()) / 
4);
+                if (levenshteinDistance(qt, dt) <= maxDist) {
+                    fuzzyFound = true;
+                }
+            }
+
+            if (!exactFound && !fuzzyFound && lowerContent.contains(qt)) {
+                substringFound = true;
+            }
+
+            if (exactFound) {
+                score += 3;
+            } else if (fuzzyFound) {
+                score += 2;
+            } else if (substringFound) {
+                score += 1;
+            }
+        }
+
+        return score;
+    }
+
+    private List<GuideSection> loadGuideSections() {
+        List<GuideSection> sections = new ArrayList<>();
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+
+        // Read index.txt to discover guide filenames
+        List<String> guideFiles = new ArrayList<>();
+        InputStream indexStream = cl.getResourceAsStream(GUIDES_INDEX_FILE);
+        if (indexStream != null) {
+            try (BufferedReader reader = new BufferedReader(new 
InputStreamReader(indexStream, StandardCharsets.UTF_8))) {
+                String line;
+                while ((line = reader.readLine()) != null) {
+                    String trimmed = line.trim();
+                    if (!trimmed.isEmpty() && trimmed.endsWith(".adoc")) {
+                        guideFiles.add(trimmed);
+                    }
+                }
+            } catch (IOException e) {
+                // fall through with empty list
+            }
+        }
+
+        for (String filename : guideFiles) {
+            InputStream is = cl.getResourceAsStream(GUIDES_RESOURCE_DIR + 
filename);
+            if (is == null) {
+                continue;
+            }
+            try (BufferedReader reader = new BufferedReader(new 
InputStreamReader(is, StandardCharsets.UTF_8))) {
+                String content = 
reader.lines().collect(Collectors.joining("\n"));
+                String guideName = guideNameFromFilename(filename);
+                String version = versionFromFilename(filename);
+                String url = urlFromFilename(filename);
+
+                splitIntoSections(content, guideName, version, url, sections);
+            } catch (IOException e) {
+                // skip unreadable files
+            }
+        }
+
+        return sections;
+    }
+
+    private void splitIntoSections(
+            String content, String guideName, String version, String url,
+            List<GuideSection> sections) {
+        String[] lines = content.split("\n");
+        StringBuilder currentContent = new StringBuilder();
+        String currentTitle = guideName;
+
+        for (String line : lines) {
+            if (line.startsWith("== ") && !line.startsWith("===")) {
+                // Flush previous section
+                if (currentContent.length() > 0) {
+                    String sectionText = currentContent.toString().trim();
+                    if (!sectionText.isEmpty()) {
+                        sections.add(new GuideSection(
+                                guideName, version, currentTitle, sectionText, 
url,
+                                tokenize(sectionText)));
+                    }
+                }
+                currentTitle = line.substring(3).trim();
+                currentContent = new StringBuilder();
+            } else {
+                currentContent.append(line).append("\n");
+            }
+        }
+
+        // Flush last section
+        if (currentContent.length() > 0) {
+            String sectionText = currentContent.toString().trim();
+            if (!sectionText.isEmpty()) {
+                sections.add(new GuideSection(
+                        guideName, version, currentTitle, sectionText, url,
+                        tokenize(sectionText)));
+            }
+        }
+    }
+
+    /**
+     * Tokenize text into lowercase words, preserving hyphens within words 
(e.g., direct-vm).
+     */
+    static List<String> tokenize(String text) {
+        String[] parts = 
text.toLowerCase(Locale.ROOT).split("[^a-zA-Z0-9\\-]+");
+        List<String> tokens = new ArrayList<>();
+        for (String part : parts) {
+            if (!part.isBlank() && part.length() > 1) {
+                tokens.add(part);
+            }
+        }
+        return tokens;
+    }
+
+    private static final LevenshteinDistance LEVENSHTEIN = 
LevenshteinDistance.getDefaultInstance();
+
+    static int levenshteinDistance(String a, String b) {
+        return LEVENSHTEIN.apply(a, b);
+    }
+
+    private static String guideNameFromFilename(String filename) {
+        String name = filename.replace(".adoc", "");
+        if ("camel-3-migration-guide".equals(name)) {
+            return "Camel 3 Migration Guide (2.x to 3.0)";
+        }
+        if ("camel-4-migration-guide".equals(name)) {
+            return "Camel 4 Migration Guide (3.x to 4.0)";
+        }
+        String version = versionFromFilename(filename);
+        return "Camel " + version + " Upgrade Guide";
+    }
+
+    private static String versionFromFilename(String filename) {
+        String name = filename.replace(".adoc", "");
+        if ("camel-3-migration-guide".equals(name)) {
+            return "3.0";
+        }
+        if ("camel-4-migration-guide".equals(name)) {
+            return "4.0";
+        }
+        int lastDash = name.lastIndexOf('-');
+        if (lastDash > 0) {
+            return name.substring(lastDash + 1).replace('_', '.');
+        }
+        return name;
+    }
+
+    private static String urlFromFilename(String filename) {
+        String name = filename.replace(".adoc", "");
+        return "https://camel.apache.org/manual/"; + name + ".html";
+    }
+
+    // Records
+
+    public record MigrationGuide(String name, String title, String url, String 
summary) {
+    }
+
+    public record GuideSection(
+            String guide,
+            String version,
+            String sectionTitle,
+            String content,
+            String url,
+            List<String> tokens) {
+    }
+
+    private record ScoredSection(GuideSection section, double score) {
+    }
+
+    public record PomAnalysis(
+            String camelVersion,
+            String springBootVersion,
+            String quarkusVersion,
+            String javaVersion,
+            List<String> dependencies,
+            boolean isWildfly,
+            boolean isKaraf) {
+
+        /**
+         * Determine the runtime type from the POM analysis.
+         */
+        public String runtimeType() {
+            if (isWildfly) {
+                return "wildfly";
+            }
+            if (isKaraf) {
+                return "karaf";
+            }
+            if (springBootVersion != null || dependencies.stream().anyMatch(d 
-> d.contains("spring-boot"))) {
+                return "spring-boot";
+            }
+            if (quarkusVersion != null || dependencies.stream().anyMatch(d -> 
d.contains("quarkus"))) {
+                return "quarkus";
+            }
+            return "main";
+        }
+
+        /**
+         * Get the major version number from the Camel version string.
+         */
+        public int majorVersion() {
+            if (camelVersion == null) {
+                return 0;
+            }
+            try {
+                return Integer.parseInt(camelVersion.split("\\.")[0]);
+            } catch (NumberFormatException e) {
+                return 0;
+            }
+        }
+    }
+}
diff --git 
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/MigrationResources.java
 
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/MigrationResources.java
new file mode 100644
index 000000000000..cd4790ef31b1
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/MigrationResources.java
@@ -0,0 +1,102 @@
+/*
+ * 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 jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+
+import io.quarkiverse.mcp.server.Resource;
+import io.quarkiverse.mcp.server.ResourceTemplate;
+import io.quarkiverse.mcp.server.ResourceTemplateArg;
+import io.quarkiverse.mcp.server.TextResourceContents;
+import org.apache.camel.util.json.JsonArray;
+import org.apache.camel.util.json.JsonObject;
+
+/**
+ * MCP Resources exposing migration guide reference data.
+ * <p>
+ * These resources provide browseable migration guide metadata that clients 
can pull into context for Camel version
+ * upgrades and runtime migrations.
+ */
+@ApplicationScoped
+public class MigrationResources {
+
+    @Inject
+    MigrationData migrationData;
+
+    /**
+     * All Camel migration guides with titles, URLs, and summaries.
+     */
+    @Resource(uri = "camel://migration/guides",
+              name = "camel_migration_guides",
+              title = "Camel Migration Guides",
+              description = "List of all Camel migration and upgrade guides 
with titles, URLs, and summaries "
+                            + "covering Camel 2.x to 3.x, 3.x to 4.x, and 
minor version upgrades.",
+              mimeType = "application/json")
+    public TextResourceContents migrationGuides() {
+        JsonObject result = new JsonObject();
+
+        JsonArray guides = new JsonArray();
+        for (MigrationData.MigrationGuide guide : 
migrationData.getMigrationGuides()) {
+            JsonObject guideJson = new JsonObject();
+            guideJson.put("name", guide.name());
+            guideJson.put("title", guide.title());
+            guideJson.put("url", guide.url());
+            guideJson.put("summary", guide.summary());
+            guides.add(guideJson);
+        }
+
+        result.put("guides", guides);
+        result.put("totalCount", guides.size());
+
+        return new TextResourceContents("camel://migration/guides", 
result.toJson(), "application/json");
+    }
+
+    /**
+     * Detail for a specific migration guide by name.
+     */
+    @ResourceTemplate(uriTemplate = "camel://migration/guide/{name}",
+                      name = "camel_migration_guide_detail",
+                      title = "Migration Guide Detail",
+                      description = "Detail for a specific Camel migration 
guide including title, URL, and summary.",
+                      mimeType = "application/json")
+    public TextResourceContents migrationGuideDetail(
+            @ResourceTemplateArg(name = "name") String name) {
+
+        String uri = "camel://migration/guide/" + name;
+
+        MigrationData.MigrationGuide guide = 
migrationData.getMigrationGuide(name);
+        if (guide == null) {
+            JsonObject result = new JsonObject();
+            result.put("name", name);
+            result.put("found", false);
+            result.put("message", "Migration guide '" + name + "' not found. "
+                                  + "Available guides: migration-and-upgrade, 
camel-3-migration, "
+                                  + "camel-4-migration, camel-3x-upgrade, 
camel-4x-upgrade.");
+            return new TextResourceContents(uri, result.toJson(), 
"application/json");
+        }
+
+        JsonObject result = new JsonObject();
+        result.put("name", guide.name());
+        result.put("found", true);
+        result.put("title", guide.title());
+        result.put("url", guide.url());
+        result.put("summary", guide.summary());
+
+        return new TextResourceContents(uri, result.toJson(), 
"application/json");
+    }
+}
diff --git 
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/MigrationTools.java
 
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/MigrationTools.java
new file mode 100644
index 000000000000..24654dd5f4c0
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/MigrationTools.java
@@ -0,0 +1,395 @@
+/*
+ * 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.List;
+import java.util.stream.Collectors;
+
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+
+import io.quarkiverse.mcp.server.Tool;
+import io.quarkiverse.mcp.server.ToolArg;
+import io.quarkiverse.mcp.server.ToolCallException;
+
+/**
+ * MCP Tools for Camel migration and upgrade workflows.
+ * <p>
+ * Provides a guided, step-by-step migration pipeline: analyze → compatibility 
→ recipes → guide search. Each tool
+ * returns a {@code nextStep} hint that guides the LLM to the next action in 
the workflow. For migration summaries, use
+ * {@code git diff --shortstat} directly.
+ */
+@ApplicationScoped
+public class MigrationTools {
+
+    private static final String OPENREWRITE_VERSION = "6.29.0";
+    private static final String CAMEL_UPGRADE_RECIPES_ARTIFACT = 
"camel-upgrade-recipes";
+    private static final String CAMEL_SPRING_BOOT_UPGRADE_RECIPES_ARTIFACT = 
"camel-spring-boot-upgrade-recipes";
+
+    @Inject
+    MigrationData migrationData;
+
+    /**
+     * Step 1: Analyze a project's pom.xml to detect runtime, Camel version, 
Java version, and components.
+     */
+    @Tool(description = "Analyze a Camel project's pom.xml to detect the 
runtime type (main, spring-boot, quarkus, "
+                        + "wildfly, karaf), Camel version, Java version, and 
Camel component dependencies. "
+                        + "This is the first step in a migration workflow.")
+    public ProjectAnalysisResult camel_migration_analyze(
+            @ToolArg(description = "The pom.xml file content") String 
pomContent) {
+
+        if (pomContent == null || pomContent.isBlank()) {
+            throw new ToolCallException("pomContent is required", null);
+        }
+
+        try {
+            MigrationData.PomAnalysis pom = 
MigrationData.parsePomContent(pomContent);
+
+            String runtimeType = pom.runtimeType();
+            int majorVersion = pom.majorVersion();
+
+            List<String> warnings = new ArrayList<>();
+            if (pom.camelVersion() == null) {
+                warnings.add("Could not detect Camel version from pom.xml. "
+                             + "Check if the version is defined in a parent 
POM.");
+            }
+            if (pom.javaVersion() == null) {
+                warnings.add("Could not detect Java version from pom.xml.");
+            }
+
+            List<String> guideUrls = 
migrationData.getGuidesForVersion(majorVersion).stream()
+                    .map(MigrationData.MigrationGuide::url)
+                    .collect(Collectors.toList());
+
+            String nextStep;
+            if ("wildfly".equals(runtimeType) || "karaf".equals(runtimeType)) {
+                nextStep = "Call camel_migration_wildfly_karaf to get 
migration guidance for " + runtimeType + ".";
+            } else {
+                nextStep = "Call camel_migration_compatibility with the 
detected components and target version.";
+            }
+
+            return new ProjectAnalysisResult(
+                    pom.camelVersion(), majorVersion, runtimeType, 
pom.javaVersion(),
+                    pom.dependencies(), warnings, guideUrls, nextStep);
+        } catch (ToolCallException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new ToolCallException("Failed to parse pom.xml: " + 
e.getMessage(), e);
+        }
+    }
+
+    /**
+     * Step 2: Check compatibility and provide relevant migration guide 
references.
+     */
+    @Tool(description = "Check migration compatibility for Camel components by 
providing relevant migration guide "
+                        + "URLs and Java version requirements. The LLM should 
consult the migration guides for "
+                        + "detailed component rename mappings and API 
changes.")
+    public CompatibilityResult camel_migration_compatibility(
+            @ToolArg(description = "Comma-separated list of Camel component 
artifactIds") String camelComponents,
+            @ToolArg(description = "Current Camel version (e.g., 3.20.0)") 
String currentVersion,
+            @ToolArg(description = "Target Camel version (e.g., 4.18.0)") 
String targetVersion,
+            @ToolArg(description = "Runtime type: main, spring-boot, or 
quarkus") String runtime,
+            @ToolArg(description = "Current Java version (e.g., 11, 17, 21)") 
String javaVersion) {
+
+        if (camelComponents == null || camelComponents.isBlank()) {
+            throw new ToolCallException("camelComponents is required", null);
+        }
+        if (currentVersion == null || currentVersion.isBlank()) {
+            throw new ToolCallException("currentVersion is required", null);
+        }
+        if (targetVersion == null || targetVersion.isBlank()) {
+            throw new ToolCallException("targetVersion is required", null);
+        }
+
+        int currentMajor = parseMajorVersion(currentVersion);
+        int targetMajor = parseMajorVersion(targetVersion);
+        boolean crossesMajorVersion = currentMajor != targetMajor;
+
+        // Java version check
+        List<String> blockers = new ArrayList<>();
+        List<String> warnings = new ArrayList<>();
+        JavaCompatibility javaCompat = null;
+
+        if (javaVersion != null && !javaVersion.isBlank()) {
+            int javaVer = parseJavaVersion(javaVersion);
+            boolean javaCompatible = true;
+            String requiredVersion = "17";
+
+            if (targetMajor >= 4 && javaVer < 17) {
+                javaCompatible = false;
+                blockers.add("Camel 4.x requires Java 17+. Current Java 
version is " + javaVersion + ".");
+            }
+
+            javaCompat = new JavaCompatibility(javaVersion, requiredVersion, 
javaCompatible);
+        }
+
+        // Collect relevant migration guides
+        List<MigrationData.MigrationGuide> guides = new ArrayList<>();
+        guides.add(migrationData.getMigrationGuide("migration-and-upgrade"));
+        if (crossesMajorVersion) {
+            if (currentMajor <= 2 && targetMajor >= 3) {
+                
guides.add(migrationData.getMigrationGuide("camel-3-migration"));
+            }
+            if (currentMajor <= 3 && targetMajor >= 4) {
+                
guides.add(migrationData.getMigrationGuide("camel-4-migration"));
+            }
+        } else {
+            if (targetMajor == 3) {
+                
guides.add(migrationData.getMigrationGuide("camel-3x-upgrade"));
+            } else if (targetMajor >= 4) {
+                
guides.add(migrationData.getMigrationGuide("camel-4x-upgrade"));
+            }
+        }
+
+        List<String> guideUrls = guides.stream()
+                .map(MigrationData.MigrationGuide::url)
+                .collect(Collectors.toList());
+
+        if (crossesMajorVersion) {
+            warnings.add("This is a major version upgrade (" + currentMajor + 
".x → " + targetMajor
+                         + ".x). Review the migration guides for component 
renames, "
+                         + "discontinued components, and API changes.");
+        }
+
+        String nextStep;
+        if (!blockers.isEmpty()) {
+            nextStep = "Resolve blockers, then call camel_migration_recipes 
for OpenRewrite commands.";
+        } else {
+            nextStep = "Call camel_migration_recipes to get the OpenRewrite 
upgrade commands.";
+        }
+
+        return new CompatibilityResult(
+                blockers.isEmpty(), guideUrls, javaCompat, warnings, blockers, 
nextStep);
+    }
+
+    /**
+     * Step 3: Get Maven commands to run OpenRewrite migration recipes.
+     */
+    @Tool(description = "Get Maven commands to run Camel OpenRewrite migration 
recipes for upgrading between versions. "
+                        + "Returns the exact Maven commands to execute on the 
project. "
+                        + "PREREQUISITE: The project MUST compile successfully 
('mvn clean compile' must pass) "
+                        + "BEFORE running the OpenRewrite recipes. If the 
project does not compile, fix the build "
+                        + "errors first. OpenRewrite requires a compilable 
project to parse and transform the code.")
+    public MigrationRecipesResult camel_migration_recipes(
+            @ToolArg(description = "Runtime type: main, spring-boot, or 
quarkus") String runtime,
+            @ToolArg(description = "Current Camel version (e.g., 4.4.0)") 
String currentVersion,
+            @ToolArg(description = "Target Camel version (e.g., 4.18.0)") 
String targetVersion,
+            @ToolArg(description = "Current Java version (e.g., 11, 17)") 
String javaVersion,
+            @ToolArg(description = "If true, perform a dry run without making 
changes (default: true)") Boolean dryRun) {
+
+        if (runtime == null || runtime.isBlank()) {
+            throw new ToolCallException("runtime is required", null);
+        }
+        if (targetVersion == null || targetVersion.isBlank()) {
+            throw new ToolCallException("targetVersion is required", null);
+        }
+
+        boolean isDryRun = dryRun == null || dryRun;
+        String runMode = isDryRun ? "dryRun" : "run";
+        List<String> mavenCommands = new ArrayList<>();
+        List<String> notes = new ArrayList<>();
+
+        String resolvedRuntime = runtime.toLowerCase().trim();
+
+        if ("quarkus".equals(resolvedRuntime)) {
+            // The quarkus-maven-plugin:update command internally uses 
OpenRewrite recipes
+            // including Camel-specific recipes (e.g., 
io.quarkus.updates.camel.camel44.CamelQuarkusMigrationRecipe)
+            // to handle both Quarkus platform and Camel Quarkus upgrades.
+            String quarkusCommand;
+            if (targetVersion != null && !targetVersion.isBlank()) {
+                quarkusCommand = String.format(
+                        "mvn --no-transfer-progress 
io.quarkus.platform:quarkus-maven-plugin:%s:update %s",
+                        targetVersion, isDryRun ? "-DrewriteDryRun" : 
"-DrewriteFullRun");
+            } else {
+                quarkusCommand = String.format(
+                        "mvn --no-transfer-progress 
io.quarkus.platform:quarkus-maven-plugin:update %s",
+                        isDryRun ? "-DrewriteDryRun" : "-DrewriteFullRun");
+            }
+            mavenCommands.add(quarkusCommand);
+            notes.add("The quarkus-maven-plugin:update command uses 
OpenRewrite under the hood. "
+                      + "It automatically applies both Quarkus platform 
upgrade recipes and Camel Quarkus "
+                      + "migration recipes (e.g., 
CamelQuarkusMigrationRecipe). "
+                      + "Do NOT use the standalone camel-upgrade-recipes 
artifact for Camel Quarkus projects — "
+                      + "the Quarkus update command already includes the 
appropriate Camel recipes.");
+            notes.add("IMPORTANT: This command only works on existing Quarkus 
projects (version 2.13+). "
+                      + "If migrating from a non-Quarkus runtime (WildFly, 
Karaf, WAR), "
+                      + "you must first create a new Quarkus project using the 
archetype from "
+                      + "camel_migration_wildfly_karaf, then run this update 
command.");
+        } else {
+            String artifact = "spring-boot".equals(resolvedRuntime)
+                    ? CAMEL_SPRING_BOOT_UPGRADE_RECIPES_ARTIFACT
+                    : CAMEL_UPGRADE_RECIPES_ARTIFACT;
+
+            String command = String.format(
+                    "mvn --no-transfer-progress 
org.openrewrite.maven:rewrite-maven-plugin:%s:%s "
+                                           + 
"-Drewrite.recipeArtifactCoordinates=org.apache.camel.upgrade:%s:%s "
+                                           + 
"-Drewrite.activeRecipes=org.apache.camel.upgrade.CamelMigrationRecipe",
+                    OPENREWRITE_VERSION, runMode, artifact, targetVersion);
+            mavenCommands.add(command);
+        }
+
+        // Java upgrade suggestion
+        List<String> javaUpgradeSuggestions = new ArrayList<>();
+        if (javaVersion != null && !javaVersion.isBlank()) {
+            int javaVer = parseJavaVersion(javaVersion);
+            if (javaVer < 17) {
+                javaUpgradeSuggestions.add(
+                        "Consider upgrading to Java 17. "
+                                           + "OpenRewrite recipe: 
org.openrewrite.java.migrate.UpgradeToJava17");
+            } else if (javaVer < 21) {
+                javaUpgradeSuggestions.add(
+                        "Consider upgrading to Java 21 for virtual threads 
support. "
+                                           + "OpenRewrite recipe: 
org.openrewrite.java.migrate.UpgradeToJava21");
+            }
+        }
+
+        String nextStep = "Verify the project compiles with 'mvn clean 
compile' before and after running the recipes.";
+
+        return new MigrationRecipesResult(
+                resolvedRuntime, currentVersion, targetVersion,
+                mavenCommands, javaUpgradeSuggestions, notes, isDryRun, 
nextStep);
+    }
+
+    /**
+     * Search migration guides for a specific term.
+     */
+    @Tool(description = "Search Camel migration and upgrade guides for a 
specific term or component name. "
+                        + "Returns matching snippets from the official guides 
with version info and URLs. "
+                        + "Supports fuzzy matching for typo tolerance. "
+                        + "Use this instead of web search when looking up 
migration-related changes, "
+                        + "removed components, API renames, or breaking 
changes.")
+    public GuideSearchResult camel_migration_guide_search(
+            @ToolArg(description = "Search query — component name, API class, 
method, or keyword "
+                                   + "(e.g., direct-vm, getOut, camel-http4, 
ExchangePattern)") String query,
+            @ToolArg(description = "Maximum number of results to return 
(default: 3)") Integer limit) {
+
+        if (query == null || query.isBlank()) {
+            throw new ToolCallException("query is required", null);
+        }
+
+        int maxResults = limit != null && limit > 0 ? limit : 3;
+        List<MigrationData.GuideSection> matches = 
migrationData.searchGuides(query, maxResults);
+
+        List<GuideSnippet> snippets = new ArrayList<>();
+        for (MigrationData.GuideSection section : matches) {
+            // Truncate content to avoid huge responses
+            String snippet = truncateSnippet(section.content(), 30);
+            snippets.add(new GuideSnippet(
+                    section.guide(), section.version(), section.sectionTitle(),
+                    snippet, section.url()));
+        }
+
+        String nextStep = "Call camel_migration_guide_search again for other 
terms, or call camel_migration_recipes.";
+
+        return new GuideSearchResult(query, snippets.size(), snippets, 
nextStep);
+    }
+
+    private String truncateSnippet(String content, int maxLines) {
+        String[] lines = content.split("\n");
+        if (lines.length <= maxLines) {
+            return content;
+        }
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < maxLines; i++) {
+            sb.append(lines[i]).append("\n");
+        }
+        sb.append("... (truncated, ").append(lines.length - maxLines).append(" 
more lines)");
+        return sb.toString();
+    }
+
+    // Helpers
+
+    private int parseMajorVersion(String version) {
+        if (version == null) {
+            return 0;
+        }
+        try {
+            return Integer.parseInt(version.split("\\.")[0]);
+        } catch (NumberFormatException e) {
+            return 0;
+        }
+    }
+
+    private int parseJavaVersion(String version) {
+        if (version == null) {
+            return 0;
+        }
+        try {
+            if (version.startsWith("1.")) {
+                return Integer.parseInt(version.substring(2));
+            }
+            return Integer.parseInt(version.split("\\.")[0]);
+        } catch (NumberFormatException e) {
+            return 0;
+        }
+    }
+
+    // Result records
+
+    public record ProjectAnalysisResult(
+            String camelVersion,
+            int majorVersion,
+            String runtimeType,
+            String javaVersion,
+            List<String> camelComponents,
+            List<String> warnings,
+            List<String> migrationGuideUrls,
+            String nextStep) {
+    }
+
+    public record CompatibilityResult(
+            boolean compatible,
+            List<String> migrationGuideUrls,
+            JavaCompatibility javaCompatibility,
+            List<String> warnings,
+            List<String> blockers,
+            String nextStep) {
+    }
+
+    public record JavaCompatibility(
+            String currentVersion,
+            String requiredVersion,
+            boolean compatible) {
+    }
+
+    public record MigrationRecipesResult(
+            String runtime,
+            String currentVersion,
+            String targetVersion,
+            List<String> mavenCommands,
+            List<String> javaUpgradeSuggestions,
+            List<String> notes,
+            boolean dryRun,
+            String nextStep) {
+    }
+
+    public record GuideSearchResult(
+            String query,
+            int resultCount,
+            List<GuideSnippet> results,
+            String nextStep) {
+    }
+
+    public record GuideSnippet(
+            String guide,
+            String version,
+            String sectionTitle,
+            String snippet,
+            String url) {
+    }
+}
diff --git 
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/MigrationWildflyKarafTools.java
 
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/MigrationWildflyKarafTools.java
new file mode 100644
index 000000000000..17f938204dc2
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/MigrationWildflyKarafTools.java
@@ -0,0 +1,179 @@
+/*
+ * 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.List;
+import java.util.stream.Collectors;
+
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+
+import io.quarkiverse.mcp.server.Tool;
+import io.quarkiverse.mcp.server.ToolArg;
+import io.quarkiverse.mcp.server.ToolCallException;
+
+/**
+ * MCP Tool for migrating Camel projects from WildFly or Karaf to modern 
runtimes.
+ * <p>
+ * Handles the special case where projects running on legacy runtimes need to 
be replatformed to Spring Boot or Quarkus.
+ * Uses Maven archetypes for new project creation and migration guides for 
component mapping details.
+ */
+@ApplicationScoped
+public class MigrationWildflyKarafTools {
+
+    @Inject
+    MigrationData migrationData;
+
+    /**
+     * WildFly/Karaf migration guidance with archetype-based project creation.
+     */
+    @Tool(description = "Get migration guidance for Camel projects running on 
WildFly, Karaf, or WAR-based "
+                        + "application servers. Returns the Maven archetype 
command to create a new target project, "
+                        + "migration steps, and relevant migration guide URLs. 
"
+                        + "IMPORTANT: When migrating to a different runtime 
(e.g., WildFly to Quarkus, Karaf to Spring Boot), "
+                        + "you MUST use the archetype command returned by this 
tool to create a new project. "
+                        + "Do NOT manually rewrite the pom.xml — always 
generate a new project with the archetype first, "
+                        + "then migrate routes and source files into it.")
+    public WildflyKarafMigrationResult camel_migration_wildfly_karaf(
+            @ToolArg(description = "The pom.xml file content of the 
WildFly/Karaf project") String pomContent,
+            @ToolArg(description = "Target runtime: spring-boot or quarkus 
(default: quarkus)") String targetRuntime,
+            @ToolArg(description = "Target Camel version (e.g., 4.18.0)") 
String targetVersion) {
+
+        if (pomContent == null || pomContent.isBlank()) {
+            throw new ToolCallException("pomContent is required", null);
+        }
+
+        try {
+            MigrationData.PomAnalysis pom = 
MigrationData.parsePomContent(pomContent);
+
+            String sourceRuntime = pom.isWildfly() ? "wildfly" : pom.isKaraf() 
? "karaf" : "unknown";
+            String resolvedTarget = targetRuntime != null && 
!targetRuntime.isBlank()
+                    ? targetRuntime.toLowerCase().trim() : "quarkus";
+
+            // Build archetype command for new project creation
+            String archetypeCommand = buildArchetypeCommand(resolvedTarget, 
targetVersion);
+
+            // Collect migration steps
+            List<String> migrationSteps = buildMigrationSteps(sourceRuntime, 
resolvedTarget);
+
+            // Collect relevant migration guides (always include 2→3 and 3→4 
for legacy projects)
+            List<MigrationData.MigrationGuide> guides = new ArrayList<>();
+            
guides.add(migrationData.getMigrationGuide("migration-and-upgrade"));
+            guides.add(migrationData.getMigrationGuide("camel-3-migration"));
+            guides.add(migrationData.getMigrationGuide("camel-4-migration"));
+            guides.add(migrationData.getMigrationGuide("camel-4x-upgrade"));
+
+            List<String> guideUrls = guides.stream()
+                    .map(MigrationData.MigrationGuide::url)
+                    .collect(Collectors.toList());
+
+            // Warnings specific to the source runtime
+            List<String> warnings = new ArrayList<>();
+            if ("karaf".equals(sourceRuntime)) {
+                warnings.add("Blueprint XML is not supported in Camel 3.x+. "
+                             + "Routes must be converted to YAML DSL, XML DSL, 
or Java DSL.");
+                warnings.add("OSGi-specific features (bundle classloading, 
service registry) "
+                             + "have no equivalent in Spring Boot or 
Quarkus.");
+            }
+            if ("wildfly".equals(sourceRuntime)) {
+                warnings.add("WildFly Camel subsystem is discontinued. "
+                             + "Migrate to Camel Spring Boot or Camel 
Quarkus.");
+            }
+
+            String nextStep = "Create a new project using the archetype 
command, migrate routes and source files, "
+                              + "then call camel_migration_recipes for 
OpenRewrite upgrade commands.";
+
+            return new WildflyKarafMigrationResult(
+                    sourceRuntime, pom.camelVersion(), resolvedTarget, 
targetVersion,
+                    pom.dependencies(), archetypeCommand, migrationSteps,
+                    guideUrls, warnings, nextStep);
+        } catch (ToolCallException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new ToolCallException("Failed to analyze WildFly/Karaf 
project: " + e.getMessage(), e);
+        }
+    }
+
+    private String buildArchetypeCommand(String targetRuntime, String 
targetVersion) {
+        if ("spring-boot".equals(targetRuntime)) {
+            // Camel Spring Boot archetype from camel-spring-boot repo
+            StringBuilder sb = new StringBuilder();
+            sb.append("mvn archetype:generate ");
+            sb.append("-DarchetypeGroupId=org.apache.camel.springboot ");
+            sb.append("-DarchetypeArtifactId=camel-archetype-spring-boot ");
+            if (targetVersion != null && !targetVersion.isBlank()) {
+                
sb.append("-DarchetypeVersion=").append(targetVersion).append(" ");
+            }
+            sb.append("-DgroupId=com.example ");
+            sb.append("-DartifactId=camel-migration-project ");
+            sb.append("-Dversion=1.0-SNAPSHOT ");
+            sb.append("-DinteractiveMode=false");
+            return sb.toString();
+        } else {
+            // Quarkus project creation with Camel extensions
+            StringBuilder sb = new StringBuilder();
+            sb.append("mvn io.quarkus.platform:quarkus-maven-plugin:create ");
+            sb.append("-DprojectGroupId=com.example ");
+            sb.append("-DprojectArtifactId=camel-migration-project ");
+            sb.append("-Dextensions=camel-quarkus-core");
+            return sb.toString();
+        }
+    }
+
+    private List<String> buildMigrationSteps(String sourceRuntime, String 
targetRuntime) {
+        List<String> steps = new ArrayList<>();
+        steps.add("Create a new " + targetRuntime + " project using the 
archetype command provided.");
+        steps.add("Review the migration guides for component renames between 
Camel 2.x and 4.x.");
+
+        if ("karaf".equals(sourceRuntime)) {
+            steps.add("Convert Blueprint XML routes to YAML DSL, XML DSL, or 
Java DSL. "
+                      + "Use the camel_transform_route tool for YAML/XML 
conversions.");
+            steps.add("Remove OSGi-specific code (bundle activators, service 
trackers, "
+                      + "MANIFEST.MF Import-Package directives).");
+        }
+
+        if ("wildfly".equals(sourceRuntime)) {
+            steps.add("Remove WildFly Camel subsystem configuration.");
+            steps.add("Convert CDI-based Camel configuration to Spring Boot or 
Quarkus patterns.");
+        }
+
+        steps.add("Add required Camel component dependencies to the new 
project's pom.xml, "
+                  + "using updated artifact names from the migration guides.");
+        steps.add("Migrate Java source files, updating package imports and API 
calls "
+                  + "per the migration guides.");
+        steps.add("Run 'mvn clean compile' to check for build errors.");
+        steps.add("Fix any remaining build errors using 
camel_migration_guide_search for reference.");
+        steps.add("Run 'mvn clean test' to validate the migration.");
+        return steps;
+    }
+
+    // Result record
+
+    public record WildflyKarafMigrationResult(
+            String sourceRuntime,
+            String sourceCamelVersion,
+            String targetRuntime,
+            String targetCamelVersion,
+            List<String> detectedDependencies,
+            String archetypeCommand,
+            List<String> migrationSteps,
+            List<String> migrationGuideUrls,
+            List<String> warnings,
+            String nextStep) {
+    }
+}
diff --git 
a/dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/MigrationDataSearchTest.java
 
b/dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/MigrationDataSearchTest.java
new file mode 100644
index 000000000000..a3d2d637d9c6
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/MigrationDataSearchTest.java
@@ -0,0 +1,64 @@
+/*
+ * 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.List;
+
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Tests that the migration guide fuzzy search works end-to-end: loads the 
real .adoc guide files from the classpath,
+ * indexes them, and returns relevant results for exact, fuzzy, and nonsense 
queries.
+ */
+class MigrationDataSearchTest {
+
+    private final MigrationData migrationData = new MigrationData();
+
+    @Test
+    void exactSearchFindsMatchingGuideSection() {
+        // "camel-vm" was removed in Camel 4 — this is documented in the 
migration guides
+        List<MigrationData.GuideSection> results = 
migrationData.searchGuides("camel-vm", 3);
+
+        assertThat(results).isNotEmpty();
+        
assertThat(results.get(0).content().toLowerCase()).contains("camel-vm");
+        
assertThat(results.get(0).url()).startsWith("https://camel.apache.org/manual/";);
+    }
+
+    @Test
+    void fuzzySearchFindsResultDespiteTypo() {
+        // "directvm" (missing hyphen) should still match "direct-vm" sections 
via fuzzy matching
+        List<MigrationData.GuideSection> results = 
migrationData.searchGuides("directvm", 3);
+
+        assertThat(results).isNotEmpty();
+    }
+
+    @Test
+    void nonsenseQueryReturnsNoResults() {
+        List<MigrationData.GuideSection> results = 
migrationData.searchGuides("xyznonexistent12345", 3);
+
+        assertThat(results).isEmpty();
+    }
+
+    @Test
+    void searchRespectsLimit() {
+        List<MigrationData.GuideSection> results = 
migrationData.searchGuides("camel", 2);
+
+        assertThat(results).hasSizeLessThanOrEqualTo(2);
+    }
+}

Reply via email to