This is an automated email from the ASF dual-hosted git repository. acosentino pushed a commit to branch 23011 in repository https://gitbox.apache.org/repos/asf/camel.git
commit 445777b5cc648662d0957d5f4d1c789a0008865c Author: Andrea Cosentino <[email protected]> AuthorDate: Mon Feb 16 13:17:04 2026 +0100 CAMEL-23011 - camel-mcp - camel_catalog_components returns Internal Server Error and in general make tools robust Signed-off-by: Andrea Cosentino <[email protected]> --- .../dsl/jbang/core/commands/mcp/CatalogTools.java | 95 ++++++++++----- .../dsl/jbang/core/commands/mcp/ExplainTools.java | 97 ++++++++------- .../dsl/jbang/core/commands/mcp/HardenTools.java | 97 ++++++++------- .../dsl/jbang/core/commands/mcp/KameletTools.java | 10 +- .../jbang/core/commands/mcp/TransformTools.java | 131 +++++++++++---------- .../dsl/jbang/core/commands/mcp/VersionTools.java | 12 +- 6 files changed, 253 insertions(+), 189 deletions(-) diff --git a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/CatalogTools.java b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/CatalogTools.java index 374e8028bcbf..983d1e8da63c 100644 --- a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/CatalogTools.java +++ b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/CatalogTools.java @@ -74,8 +74,11 @@ public class CatalogTools { .collect(Collectors.toList()); return new ComponentListResult(components.size(), cat.getCatalogVersion(), components); - } catch (Exception e) { - throw new ToolCallException("Failed to list components: " + e.getMessage(), e); + } catch (ToolCallException e) { + throw e; + } catch (Throwable e) { + throw new ToolCallException( + "Failed to list components (" + e.getClass().getName() + "): " + e.getMessage(), null); } } @@ -103,8 +106,9 @@ public class CatalogTools { return toComponentDetailResult(model); } catch (ToolCallException e) { throw e; - } catch (Exception e) { - throw new ToolCallException("Failed to get component doc: " + e.getMessage(), e); + } catch (Throwable e) { + throw new ToolCallException( + "Component not found: " + component + " (" + e.getClass().getName() + "): " + e.getMessage(), null); } } @@ -129,8 +133,9 @@ public class CatalogTools { .collect(Collectors.toList()); return new DataFormatListResult(dataFormats.size(), dataFormats); - } catch (Exception e) { - throw new ToolCallException("Failed to list data formats: " + e.getMessage(), e); + } catch (Throwable e) { + throw new ToolCallException( + "Failed to list data formats (" + e.getClass().getName() + "): " + e.getMessage(), null); } } @@ -151,8 +156,9 @@ public class CatalogTools { .collect(Collectors.toList()); return new LanguageListResult(languages.size(), languages); - } catch (Exception e) { - throw new ToolCallException("Failed to list languages: " + e.getMessage(), e); + } catch (Throwable e) { + throw new ToolCallException( + "Failed to list languages (" + e.getClass().getName() + "): " + e.getMessage(), null); } } @@ -168,12 +174,20 @@ public class CatalogTools { throw new ToolCallException("Data format name is required", null); } - DataFormatModel model = catalog.dataFormatModel(dataformat); - if (model == null) { - throw new ToolCallException("Data format not found: " + dataformat, null); - } + try { + DataFormatModel model = catalog.dataFormatModel(dataformat); + if (model == null) { + throw new ToolCallException("Data format not found: " + dataformat, null); + } - return toDataFormatDetailResult(model); + return toDataFormatDetailResult(model); + } catch (ToolCallException e) { + throw e; + } catch (Throwable e) { + throw new ToolCallException( + "Data format not found: " + dataformat + " (" + e.getClass().getName() + "): " + e.getMessage(), + null); + } } /** @@ -188,12 +202,19 @@ public class CatalogTools { throw new ToolCallException("Language name is required", null); } - LanguageModel model = catalog.languageModel(language); - if (model == null) { - throw new ToolCallException("Language not found: " + language, null); - } + try { + LanguageModel model = catalog.languageModel(language); + if (model == null) { + throw new ToolCallException("Language not found: " + language, null); + } - return toLanguageDetailResult(model); + return toLanguageDetailResult(model); + } catch (ToolCallException e) { + throw e; + } catch (Throwable e) { + throw new ToolCallException( + "Language not found: " + language + " (" + e.getClass().getName() + "): " + e.getMessage(), null); + } } /** @@ -215,8 +236,9 @@ public class CatalogTools { .collect(Collectors.toList()); return new EipListResult(eips.size(), eips); - } catch (Exception e) { - throw new ToolCallException("Failed to list EIPs: " + e.getMessage(), e); + } catch (Throwable e) { + throw new ToolCallException( + "Failed to list EIPs (" + e.getClass().getName() + "): " + e.getMessage(), null); } } @@ -231,12 +253,19 @@ public class CatalogTools { throw new ToolCallException("EIP name is required", null); } - EipModel model = catalog.eipModel(eip); - if (model == null) { - throw new ToolCallException("EIP not found: " + eip, null); - } + try { + EipModel model = catalog.eipModel(eip); + if (model == null) { + throw new ToolCallException("EIP not found: " + eip, null); + } - return toEipDetailResult(model); + return toEipDetailResult(model); + } catch (ToolCallException e) { + throw e; + } catch (Throwable e) { + throw new ToolCallException( + "EIP not found: " + eip + " (" + e.getClass().getName() + "): " + e.getMessage(), null); + } } // Catalog loading @@ -255,11 +284,7 @@ public class CatalogTools { } // No specific version, use runtime-specific catalog or default - if (runtime == null || runtime.isBlank() || "main".equalsIgnoreCase(runtime)) { - return catalog; - } - - RuntimeType runtimeType = RuntimeType.fromValue(runtime); + RuntimeType runtimeType = resolveRuntime(runtime); if (runtimeType == RuntimeType.springBoot) { return CatalogLoader.loadSpringBootCatalog(null, null, true); } else if (runtimeType == RuntimeType.quarkus) { @@ -273,11 +298,19 @@ public class CatalogTools { if (runtime == null || runtime.isBlank() || "main".equalsIgnoreCase(runtime)) { return RuntimeType.main; } - return RuntimeType.fromValue(runtime); + try { + return RuntimeType.fromValue(runtime); + } catch (IllegalArgumentException e) { + throw new ToolCallException( + "Unsupported runtime: " + runtime + ". Supported values are: main, spring-boot, quarkus", null); + } } private static List<String> findComponentNames(CamelCatalog catalog) { List<String> answer = catalog.findComponentNames(); + if (answer == null) { + return new ArrayList<>(); + } List<String> copy = new ArrayList<>(answer); copy.removeIf(String::isBlank); return copy; diff --git a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/ExplainTools.java b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/ExplainTools.java index 6e24a7da9d13..49e63fc2b345 100644 --- a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/ExplainTools.java +++ b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/ExplainTools.java @@ -61,54 +61,61 @@ public class ExplainTools { 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); - - // Extract and document components - List<String> componentNames = extractComponents(route); - JsonArray components = new JsonArray(); - for (String comp : componentNames) { - 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("syntax", model.getSyntax()); - compJson.put("producerOnly", model.isProducerOnly()); - compJson.put("consumerOnly", model.isConsumerOnly()); - components.add(compJson); + try { + String resolvedFormat = format != null && !format.isBlank() ? format.toLowerCase() : "yaml"; + + JsonObject result = new JsonObject(); + result.put("format", resolvedFormat); + result.put("route", route); + + // Extract and document components + List<String> componentNames = extractComponents(route); + JsonArray components = new JsonArray(); + for (String comp : componentNames) { + 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("syntax", model.getSyntax()); + compJson.put("producerOnly", model.isProducerOnly()); + compJson.put("consumerOnly", model.isConsumerOnly()); + components.add(compJson); + } } - } - result.put("components", components); - - // Extract and document EIPs - List<String> eipNames = extractEips(route); - JsonArray eips = new JsonArray(); - for (String eip : eipNames) { - EipModel model = catalog.eipModel(eip); - if (model != null) { - JsonObject eipJson = new JsonObject(); - eipJson.put("name", eip); - eipJson.put("title", model.getTitle()); - eipJson.put("description", model.getDescription()); - eipJson.put("label", model.getLabel()); - eips.add(eipJson); + result.put("components", components); + + // Extract and document EIPs + List<String> eipNames = extractEips(route); + JsonArray eips = new JsonArray(); + for (String eip : eipNames) { + EipModel model = catalog.eipModel(eip); + if (model != null) { + JsonObject eipJson = new JsonObject(); + eipJson.put("name", eip); + eipJson.put("title", model.getTitle()); + eipJson.put("description", model.getDescription()); + eipJson.put("label", model.getLabel()); + eips.add(eipJson); + } } + result.put("eips", eips); + + // Add summary counts + JsonObject summary = new JsonObject(); + summary.put("componentCount", components.size()); + summary.put("eipCount", eips.size()); + result.put("summary", summary); + + return result.toJson(); + } catch (ToolCallException e) { + throw e; + } catch (Throwable e) { + throw new ToolCallException( + "Failed to get route context (" + e.getClass().getName() + "): " + e.getMessage(), null); } - result.put("eips", eips); - - // Add summary counts - JsonObject summary = new JsonObject(); - summary.put("componentCount", components.size()); - summary.put("eipCount", eips.size()); - result.put("summary", summary); - - return result.toJson(); } /** 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 index fcf59714c837..6202a5e0e3aa 100644 --- 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 @@ -64,55 +64,62 @@ public class HardenTools { 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", securityData.getSecurityConsiderations(comp)); - compJson.put("riskLevel", securityData.getRiskLevel(comp)); - securityComponentsJson.add(compJson); + try { + 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", securityData.getSecurityConsiderations(comp)); + compJson.put("riskLevel", securityData.getRiskLevel(comp)); + securityComponentsJson.add(compJson); + } } - } - result.put("securitySensitiveComponents", securityComponentsJson); + result.put("securitySensitiveComponents", securityComponentsJson); - // Security analysis - JsonObject securityAnalysis = analyzeSecurityConcerns(route); - result.put("securityAnalysis", securityAnalysis); + // Security analysis + JsonObject securityAnalysis = analyzeSecurityConcerns(route); + result.put("securityAnalysis", securityAnalysis); - // Best practices - JsonArray bestPractices = new JsonArray(); - for (String practice : securityData.getBestPractices()) { - bestPractices.add(practice); + // Best practices + JsonArray bestPractices = new JsonArray(); + for (String practice : securityData.getBestPractices()) { + 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(); + } catch (ToolCallException e) { + throw e; + } catch (Throwable e) { + throw new ToolCallException( + "Failed to analyze route security (" + e.getClass().getName() + "): " + e.getMessage(), null); } - 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(); } /** diff --git a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/KameletTools.java b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/KameletTools.java index 61e1d8a06ed9..71b83e8d9e10 100644 --- a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/KameletTools.java +++ b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/KameletTools.java @@ -88,8 +88,9 @@ public class KameletTools { result.sort((a, b) -> a.name().compareToIgnoreCase(b.name())); return new KameletListResult(result.size(), version, result); - } catch (Exception e) { - throw new ToolCallException("Failed to list kamelets: " + e.getMessage(), e); + } catch (Throwable e) { + throw new ToolCallException( + "Failed to list kamelets (" + e.getClass().getName() + "): " + e.getMessage(), null); } } @@ -138,8 +139,9 @@ public class KameletTools { km.dependencies); } catch (ToolCallException e) { throw e; - } catch (Exception e) { - throw new ToolCallException("Failed to get kamelet doc: " + e.getMessage(), e); + } catch (Throwable e) { + throw new ToolCallException( + "Kamelet not found: " + kamelet + " (" + e.getClass().getName() + "): " + e.getMessage(), null); } } diff --git a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/TransformTools.java b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/TransformTools.java index fae26b231f53..cc24017392cc 100644 --- a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/TransformTools.java +++ b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/TransformTools.java @@ -70,74 +70,81 @@ public class TransformTools { throw new ToolCallException("Either 'uri' or 'route' is required", null); } - ValidationResult result = new ValidationResult(); + try { + ValidationResult result = new ValidationResult(); - if (uri != null) { - result.uri = uri; - EndpointValidationResult validation = catalog.validateEndpointProperties(uri); - result.valid = validation.isSuccess(); + if (uri != null) { + result.uri = uri; + EndpointValidationResult validation = catalog.validateEndpointProperties(uri); + result.valid = validation.isSuccess(); - if (!validation.isSuccess()) { - ValidationErrors errors = new ValidationErrors(); - if (validation.getUnknown() != null && !validation.getUnknown().isEmpty()) { - errors.unknownOptions = String.join(", ", validation.getUnknown()); - } - if (validation.getRequired() != null && !validation.getRequired().isEmpty()) { - errors.missingRequired = String.join(", ", validation.getRequired()); - } - if (validation.getInvalidEnum() != null && !validation.getInvalidEnum().isEmpty()) { - errors.invalidEnumValues = validation.getInvalidEnum().toString(); - } - if (validation.getInvalidInteger() != null && !validation.getInvalidInteger().isEmpty()) { - errors.invalidIntegers = validation.getInvalidInteger().toString(); - } - if (validation.getInvalidBoolean() != null && !validation.getInvalidBoolean().isEmpty()) { - errors.invalidBooleans = validation.getInvalidBoolean().toString(); - } - if (validation.getSyntaxError() != null) { - errors.syntaxError = validation.getSyntaxError(); - } - result.errors = errors; - - if (validation.getUnknown() != null && validation.getUnknownSuggestions() != null) { - Map<String, String> suggestions = new HashMap<>(); - for (String unknown : validation.getUnknown()) { - String[] suggestionArr = validation.getUnknownSuggestions().get(unknown); - if (suggestionArr != null && suggestionArr.length > 0) { - suggestions.put(unknown, String.join(", ", suggestionArr)); - } + if (!validation.isSuccess()) { + ValidationErrors errors = new ValidationErrors(); + if (validation.getUnknown() != null && !validation.getUnknown().isEmpty()) { + errors.unknownOptions = String.join(", ", validation.getUnknown()); + } + if (validation.getRequired() != null && !validation.getRequired().isEmpty()) { + errors.missingRequired = String.join(", ", validation.getRequired()); + } + if (validation.getInvalidEnum() != null && !validation.getInvalidEnum().isEmpty()) { + errors.invalidEnumValues = validation.getInvalidEnum().toString(); + } + if (validation.getInvalidInteger() != null && !validation.getInvalidInteger().isEmpty()) { + errors.invalidIntegers = validation.getInvalidInteger().toString(); } - if (!suggestions.isEmpty()) { - result.suggestions = suggestions; + if (validation.getInvalidBoolean() != null && !validation.getInvalidBoolean().isEmpty()) { + errors.invalidBooleans = validation.getInvalidBoolean().toString(); + } + if (validation.getSyntaxError() != null) { + errors.syntaxError = validation.getSyntaxError(); + } + result.errors = errors; + + if (validation.getUnknown() != null && validation.getUnknownSuggestions() != null) { + Map<String, String> suggestions = new HashMap<>(); + for (String unknown : validation.getUnknown()) { + String[] suggestionArr = validation.getUnknownSuggestions().get(unknown); + if (suggestionArr != null && suggestionArr.length > 0) { + suggestions.put(unknown, String.join(", ", suggestionArr)); + } + } + if (!suggestions.isEmpty()) { + result.suggestions = suggestions; + } } } } - } - if (route != null) { - result.routeProvided = true; - result.note = "Full route validation requires loading the route into a CamelContext. " + - "Use 'camel run --validate' for complete validation."; - - List<String> uris = extractUrisFromRoute(route); - if (!uris.isEmpty()) { - Map<String, Boolean> uriValidations = new HashMap<>(); - boolean allValid = true; - for (String extractedUri : uris) { - EndpointValidationResult validation = catalog.validateEndpointProperties(extractedUri); - uriValidations.put(extractedUri, validation.isSuccess()); - if (!validation.isSuccess()) { - allValid = false; + if (route != null) { + result.routeProvided = true; + result.note = "Full route validation requires loading the route into a CamelContext. " + + "Use 'camel run --validate' for complete validation."; + + List<String> uris = extractUrisFromRoute(route); + if (!uris.isEmpty()) { + Map<String, Boolean> uriValidations = new HashMap<>(); + boolean allValid = true; + for (String extractedUri : uris) { + EndpointValidationResult validation = catalog.validateEndpointProperties(extractedUri); + uriValidations.put(extractedUri, validation.isSuccess()); + if (!validation.isSuccess()) { + allValid = false; + } } + result.uriValidations = uriValidations; + result.valid = allValid; + } else { + result.valid = true; } - result.uriValidations = uriValidations; - result.valid = allValid; - } else { - result.valid = true; } - } - return result; + return result; + } catch (ToolCallException e) { + throw e; + } catch (Throwable e) { + throw new ToolCallException( + "Failed to validate route (" + e.getClass().getName() + "): " + e.getMessage(), null); + } } /** @@ -185,8 +192,9 @@ public class TransformTools { result.supported = false; result.note = "Unsupported transformation: " + fromFormat + " to " + toFormat; } - } catch (Exception e) { - throw new ToolCallException("Failed to transform route: " + e.getMessage(), e); + } catch (Throwable e) { + throw new ToolCallException( + "Failed to transform route (" + e.getClass().getName() + "): " + e.getMessage(), null); } return result; @@ -284,8 +292,9 @@ public class TransformTools { } finally { tempFile.delete(); } - } catch (Exception e) { - throw new ToolCallException("Failed to validate YAML DSL: " + e.getMessage(), e); + } catch (Throwable e) { + throw new ToolCallException( + "Failed to validate YAML DSL (" + e.getClass().getName() + "): " + e.getMessage(), null); } } diff --git a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/VersionTools.java b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/VersionTools.java index eaced47c0bba..e248331082b6 100644 --- a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/VersionTools.java +++ b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/VersionTools.java @@ -93,8 +93,9 @@ public class VersionTools { return new VersionListResult(versionInfos.size(), versionInfos); } catch (ToolCallException e) { throw e; - } catch (Exception e) { - throw new ToolCallException("Failed to list versions: " + e.getMessage(), e); + } catch (Throwable e) { + throw new ToolCallException( + "Failed to list versions (" + e.getClass().getName() + "): " + e.getMessage(), null); } } @@ -102,7 +103,12 @@ public class VersionTools { if (runtime == null || runtime.isBlank() || "main".equalsIgnoreCase(runtime)) { return RuntimeType.main; } - return RuntimeType.fromValue(runtime); + try { + return RuntimeType.fromValue(runtime); + } catch (IllegalArgumentException e) { + throw new ToolCallException( + "Unsupported runtime: " + runtime + ". Supported values are: main, spring-boot, quarkus", null); + } } // Result classes for Jackson serialization
