diff --git a/dap-tool-core/src/main/java/io/shinhanlife/dap/mcc/service/ToolRegistryHeartbeatSender.java b/dap-tool-core/src/main/java/io/shinhanlife/dap/mcc/service/ToolRegistryHeartbeatSender.java index 5c453a7..1cd712c 100644 --- a/dap-tool-core/src/main/java/io/shinhanlife/dap/mcc/service/ToolRegistryHeartbeatSender.java +++ b/dap-tool-core/src/main/java/io/shinhanlife/dap/mcc/service/ToolRegistryHeartbeatSender.java @@ -120,10 +120,7 @@ public class ToolRegistryHeartbeatSender { if (method.getParameterCount() > 0) { try { Class paramType = method.getParameterTypes()[0]; - Map schema = JsonSchemaGenerator.generatePropertiesSchema(paramType); - Map finalSchema = new HashMap<>(); - finalSchema.put("type", "object"); - finalSchema.put("properties", schema); + Map finalSchema = JsonSchemaGenerator.generateSchema(paramType); meta.setParametersSchema(finalSchema); } catch (Exception e) { log.error("Failed to generate schema for {}", subToolName, e); diff --git a/dap-tool-core/src/main/java/io/shinhanlife/dap/mcc/util/JsonSchemaGenerator.java b/dap-tool-core/src/main/java/io/shinhanlife/dap/mcc/util/JsonSchemaGenerator.java index 17470d8..ceed655 100644 --- a/dap-tool-core/src/main/java/io/shinhanlife/dap/mcc/util/JsonSchemaGenerator.java +++ b/dap-tool-core/src/main/java/io/shinhanlife/dap/mcc/util/JsonSchemaGenerator.java @@ -1,62 +1,68 @@ -package io.shinhanlife.dap.mcc.util; - - -/** - * @package io.shinhanlife.dap.mcc.util - * @className JsonSchemaGenerator - * @description AX HUB 시스템 처리 클래스 - * @author 김형식 - * @create 2026.09.01 - *
- * ---------- 개정이력 ----------
- * 수정일      수정자    수정내용
- * ---------- -------- ---------------------------
- * 2026.09.01  김형식    최초생성
- * 
- * 
- */ -import io.shinhanlife.dap.mcc.annotation.McpParameter; -import java.lang.reflect.Field; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class JsonSchemaGenerator { - - /** - * Java DTO 클래스를 분석하여 MCP 규격의 JSON Schema (Properties)를 생성합니다. - */ - public static Map generatePropertiesSchema(Class clazz) { - Map properties = new HashMap<>(); - - for (Field field : clazz.getDeclaredFields()) { - Map fieldSchema = new HashMap<>(); - - // 1. 타입 매핑 - fieldSchema.put("type", mapJavaTypeToJsonType(field.getType())); - - // 2. 어노테이션 기반 설명 추출 - McpParameter paramAnnotation = field.getAnnotation(McpParameter.class); - if (paramAnnotation != null && !paramAnnotation.description().isEmpty()) { - fieldSchema.put("description", paramAnnotation.description()); - } else { - fieldSchema.put("description", field.getName()); // 기본값 - } - - properties.put(field.getName(), fieldSchema); - } - - return properties; - } - - private static String mapJavaTypeToJsonType(Class clazz) { - if (clazz == String.class) return "string"; - if (clazz == Integer.class || clazz == int.class) return "integer"; - if (clazz == Long.class || clazz == long.class) return "integer"; - if (clazz == Double.class || clazz == double.class) return "number"; - if (clazz == Float.class || clazz == float.class) return "number"; - if (clazz == Boolean.class || clazz == boolean.class) return "boolean"; - if (List.class.isAssignableFrom(clazz)) return "array"; - return "object"; - } -} \ No newline at end of file +package io.shinhanlife.dap.mcc.util; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyDescription; +import io.shinhanlife.dap.mcc.annotation.McpParameter; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class JsonSchemaGenerator { + + /** + * Java DTO 클래스를 분석하여 MCP 규격의 완전한 JSON Schema를 생성합니다. + */ + public static Map generateSchema(Class clazz) { + Map schema = new HashMap<>(); + schema.put("type", "object"); + + Map properties = new HashMap<>(); + List requiredList = new ArrayList<>(); + + for (Field field : clazz.getDeclaredFields()) { + Map fieldSchema = new HashMap<>(); + + // 1. 타입 매핑 + fieldSchema.put("type", mapJavaTypeToJsonType(field.getType())); + + // 2. 어노테이션 기반 설명 추출 + McpParameter paramAnnotation = field.getAnnotation(McpParameter.class); + JsonPropertyDescription descAnnotation = field.getAnnotation(JsonPropertyDescription.class); + if (paramAnnotation != null && !paramAnnotation.description().isEmpty()) { + fieldSchema.put("description", paramAnnotation.description()); + } else if (descAnnotation != null && !descAnnotation.value().isEmpty()) { + fieldSchema.put("description", descAnnotation.value()); + } else { + fieldSchema.put("description", field.getName()); // 기본값 + } + + // 3. 필수 여부 판단 + JsonProperty jsonProp = field.getAnnotation(JsonProperty.class); + if ((jsonProp != null && jsonProp.required()) || (paramAnnotation != null && paramAnnotation.required())) { + requiredList.add(field.getName()); + } + + properties.put(field.getName(), fieldSchema); + } + + schema.put("properties", properties); + if (!requiredList.isEmpty()) { + schema.put("required", requiredList); + } + + return schema; + } + + private static String mapJavaTypeToJsonType(Class clazz) { + if (clazz == String.class) return "string"; + if (clazz == Integer.class || clazz == int.class) return "integer"; + if (clazz == Long.class || clazz == long.class) return "integer"; + if (clazz == Double.class || clazz == double.class) return "number"; + if (clazz == Float.class || clazz == float.class) return "number"; + if (clazz == Boolean.class || clazz == boolean.class) return "boolean"; + if (List.class.isAssignableFrom(clazz)) return "array"; + return "object"; + } +} \ No newline at end of file