chore: downgrade to spring boot 3.5
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 2m43s

This commit is contained in:
jade
2026-08-07 13:07:08 +09:00
parent d1f202aa9a
commit 782dee0d19
58 changed files with 111 additions and 77 deletions

View File

@@ -12,7 +12,7 @@ dependencies {
api 'io.github.resilience4j:resilience4j-circuitbreaker:2.2.0'
api 'io.github.resilience4j:resilience4j-ratelimiter'
api 'io.github.resilience4j:resilience4j-retry:2.2.0'
api 'org.springframework.boot:spring-boot-starter-aop:3.3.0'
api 'org.springframework.boot:spring-boot-starter-aop'
api 'org.springframework.boot:spring-boot-starter-jdbc'
api 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.3'
@@ -26,6 +26,7 @@ dependencies {
api 'com.fasterxml.jackson.core:jackson-databind:2.17.1'
api 'com.networknt:json-schema-validator:3.0.0'
api 'org.springframework.ai:spring-ai-starter-mcp-server-webmvc'
api 'org.springaicommunity:mcp-annotations:0.9.0'
api 'org.springframework.kafka:spring-kafka:3.2.0'
api 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.5.0'
}

View File

@@ -23,7 +23,7 @@ import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.ai.mcp.annotation.McpTool;
import org.springaicommunity.mcp.annotation.McpTool;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
@@ -36,7 +36,7 @@ public class ToolSlaMonitoringAspect {
private final McpProperties mcpProperties;
// @McpTool 어노테이션이 붙은 모든 비즈니스 툴 메서드 실행을 가로챕니다.
@Around("@annotation(org.springframework.ai.mcp.annotation.McpTool)")
@Around("@annotation(org.springaicommunity.mcp.annotation.McpTool)")
public Object monitorToolSla(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();

View File

@@ -10,6 +10,7 @@ import io.shinhanlife.dap.lib.mcp.ToolRegistryHeartbeatSender;
import io.shinhanlife.dap.lib.mcp.McpRequestHeaderContext;
import io.shinhanlife.dap.lib.mcp.McpRequestHeaders;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
@@ -46,12 +47,14 @@ public class ToolPodMcpToolSynchronizer {
McpSchema.Tool mcpTool = McpSchema.Tool.builder()
.name(tool.getName())
.description(tool.getDescription() == null || tool.getDescription().isBlank() ? tool.getName() + " Tool" : tool.getDescription())
.inputSchema(tool.getParametersSchema() == null ? emptySchema() : tool.getParametersSchema())
.annotations(McpSchema.ToolAnnotations.builder()
.readOnlyHint(Boolean.TRUE.equals(tool.getReadOnlyHint()))
.destructiveHint(Boolean.TRUE.equals(tool.getDestructiveHint()))
.idempotentHint(Boolean.TRUE.equals(tool.getIdempotentHint()))
.openWorldHint(Boolean.TRUE.equals(tool.getOpenWorldHint())).build())
.inputSchema(toJsonSchema(tool.getParametersSchema()))
.annotations(new McpSchema.ToolAnnotations(
tool.getDisplayName(),
tool.getReadOnlyHint(),
tool.getDestructiveHint(),
tool.getIdempotentHint(),
tool.getOpenWorldHint(),
null))
.build();
return McpServerFeatures.SyncToolSpecification.builder().tool(mcpTool)
.callHandler((context, request) -> invoke(tool.getName(), McpRequestHeaderContext.current(), request.arguments())).build();
@@ -83,4 +86,19 @@ public class ToolPodMcpToolSynchronizer {
schema.put("additionalProperties", false);
return schema;
}
}
@SuppressWarnings("unchecked")
private McpSchema.JsonSchema toJsonSchema(Map<String, Object> source) {
Map<String, Object> schema = source == null ? emptySchema() : source;
return new McpSchema.JsonSchema(
String.valueOf(schema.getOrDefault("type", "object")),
schema.get("properties") instanceof Map<?, ?> properties
? (Map<String, Object>) properties : Map.of(),
schema.get("required") instanceof List<?> required
? (List<String>) required : List.of(),
schema.get("additionalProperties") instanceof Boolean additionalProperties
? additionalProperties : Boolean.TRUE,
schema.get("$defs") instanceof Map<?, ?> defs ? (Map<String, Object>) defs : Map.of(),
schema.get("definitions") instanceof Map<?, ?> definitions
? (Map<String, Object>) definitions : Map.of());
}
}

View File

@@ -16,7 +16,7 @@ package io.shinhanlife.dap.lib.mcp;
* </pre>
*/
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.ai.mcp.annotation.McpTool;
import org.springaicommunity.mcp.annotation.McpTool;
import io.shinhanlife.dap.lib.annotation.ToolHint;
import io.shinhanlife.dap.lib.config.McpProperties;
import io.shinhanlife.dap.mcc.dto.ToolMetadata;

View File

@@ -2,7 +2,7 @@ package io.shinhanlife.dap.lib.util;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
import org.springframework.ai.mcp.annotation.McpToolParam;
import org.springaicommunity.mcp.annotation.McpToolParam;
import io.swagger.v3.oas.annotations.media.Schema;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;

View File

@@ -1,7 +1,7 @@
package io.shinhanlife.dap.lib.util;
import org.springframework.ai.mcp.annotation.McpToolParam;
import org.springaicommunity.mcp.annotation.McpToolParam;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -227,7 +227,7 @@ public class ToolScaffolder {
String serviceInterfaceContent = """
package %s.usecase;
import org.springframework.ai.mcp.annotation.McpTool;
import org.springaicommunity.mcp.annotation.McpTool;
import io.shinhanlife.dap.lib.annotation.ToolHint;
import %s.dto.%sRequest;
import %s.dto.%sResponse;

View File

@@ -18,7 +18,7 @@ public class ToolSchemaResolver {
this.objectMapper = objectMapper;
}
public Map<String, Object> resolve(org.springframework.ai.mcp.annotation.McpTool function, ToolHint hint, Class<?> requestType) {
public Map<String, Object> resolve(org.springaicommunity.mcp.annotation.McpTool function, ToolHint hint, Class<?> requestType) {
if (hint != null && !hint.inputSchemaResource().isBlank()) {
return loadResource(hint.inputSchemaResource());
}
@@ -31,7 +31,7 @@ public class ToolSchemaResolver {
* ToolHint.outputSchemaResource()가 있으면 classpath JSON 파일에서 로드하고,
* 없으면 responseType DTO를 분석하여 자동 생성합니다.
*/
public Map<String, Object> resolveOutput(org.springframework.ai.mcp.annotation.McpTool function, Class<?> responseType, ToolHint hint) {
public Map<String, Object> resolveOutput(org.springaicommunity.mcp.annotation.McpTool function, Class<?> responseType, ToolHint hint) {
if (hint != null && !hint.outputSchemaResource().isBlank()) {
return loadResource(hint.outputSchemaResource());
}
@@ -42,7 +42,7 @@ public class ToolSchemaResolver {
* Resolves an explicitly declared response schema.
* Response schemas are opt-in so existing tools keep their current response behavior.
*/
public Map<String, Object> resolveOutput(org.springframework.ai.mcp.annotation.McpTool function, Class<?> responseType) {
public Map<String, Object> resolveOutput(org.springaicommunity.mcp.annotation.McpTool function, Class<?> responseType) {
// Object, Map 등 구체적인 DTO가 아닌 경우 검증 스킵
if (responseType == null
|| responseType == Object.class
@@ -57,7 +57,7 @@ public class ToolSchemaResolver {
/**
* Retained for callers that use only explicit output schemas.
*/
public Map<String, Object> resolveOutput(org.springframework.ai.mcp.annotation.McpTool function) {
public Map<String, Object> resolveOutput(org.springaicommunity.mcp.annotation.McpTool function) {
return resolveOutput(function, null);
}

View File

@@ -17,7 +17,7 @@ package io.shinhanlife.dap.mcc.presentation;
*/
import com.fasterxml.jackson.databind.ObjectMapper;
import com.networknt.schema.Error;
import org.springframework.ai.mcp.annotation.McpTool;
import org.springaicommunity.mcp.annotation.McpTool;
import io.shinhanlife.dap.lib.validation.ToolArgumentSchemaValidator;
import io.shinhanlife.dap.lib.config.McpProperties;
import io.shinhanlife.dap.mcc.dto.ToolMetadata;

View File

@@ -1,7 +1,7 @@
package io.shinhanlife.dap.lib.util;
import org.springframework.ai.mcp.annotation.McpToolParam;
import org.springaicommunity.mcp.annotation.McpToolParam;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

View File

@@ -8,7 +8,7 @@ import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.springframework.ai.mcp.annotation.McpTool;
import org.springaicommunity.mcp.annotation.McpTool;
class ToolSchemaResolverTest {

View File

@@ -18,7 +18,7 @@ class ToolSourceUpdaterTest {
Files.createDirectories(source.getParent());
Files.writeString(source, """
package example;
import org.springframework.ai.mcp.annotation.McpTool;
import org.springaicommunity.mcp.annotation.McpTool;
import io.shinhanlife.dap.lib.annotation.ToolHint;
interface SampleUseCase {
@McpTool(name = "oth.cmm.sample.search", description = "old")

View File

@@ -90,7 +90,7 @@ class McpToolNameValidatorTest {
Files.writeString(source, """
package example;
import org.springframework.ai.mcp.annotation.McpTool;
import org.springaicommunity.mcp.annotation.McpTool;
class %s {
@McpTool(name = "%s")