feat(mcp): expose tool guidance in metadata
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 5m4s
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 5m4s
This commit is contained in:
@@ -192,7 +192,9 @@ public class McpRouterController {
|
||||
meta.put("owner_org", t.getOwnerOrg());
|
||||
meta.put("legacy_interface_id", t.getMciServiceId());
|
||||
meta.put("display_description", t.getDisplayDescription());
|
||||
meta.put("example_queries", t.getExampleQueries());
|
||||
meta.put("when_to_use", t.getWhenToUse());
|
||||
meta.put("when_not_to_use", t.getWhenNotToUse());
|
||||
meta.put("io_limits", t.getIoLimits());
|
||||
meta.put("example_queries", t.getExampleQueries());
|
||||
meta.put("required_env_keys", t.getRequiredEnvKeys());
|
||||
|
||||
|
||||
@@ -32,6 +32,9 @@ public final class ToolMetadataMcpMapper {
|
||||
put(meta, "version", metadata.getSemver());
|
||||
put(meta, "category_key", metadata.getCategoryKey());
|
||||
put(meta, "display_description", metadata.getDisplayDescription());
|
||||
put(meta, "when_to_use", metadata.getWhenToUse());
|
||||
put(meta, "when_not_to_use", metadata.getWhenNotToUse());
|
||||
put(meta, "io_limits", metadata.getIoLimits());
|
||||
put(meta, "example_queries", metadata.getExampleQueries());
|
||||
put(meta, "tags", metadata.getTags());
|
||||
put(meta, "legacy_interface_id", metadata.getMciServiceId());
|
||||
|
||||
@@ -207,10 +207,7 @@ public class ToolRegistryHeartbeatSender {
|
||||
meta.setWhenToUse(definition.description().whenToUse());
|
||||
meta.setWhenNotToUse(definition.description().whenNotToUse());
|
||||
meta.setIoLimits(definition.description().ioLimits());
|
||||
meta.setDescription(String.join("\n", definition.description().function(),
|
||||
"사용 시점: " + definition.description().whenToUse(),
|
||||
"사용 제외: " + definition.description().whenNotToUse(),
|
||||
"입출력 제한: " + definition.description().ioLimits()));
|
||||
meta.setDescription(definition.description().function());
|
||||
meta.setDisplayDescription(definition.displayDescription());
|
||||
meta.setExampleQueries(definition.exampleQueries());
|
||||
meta.setReadOnlyHint(definition.readOnly());
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package io.shinhanlife.dap.lib.mcp;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import io.shinhanlife.dap.mcc.dto.ToolMetadata;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class ToolMetadataMcpMapperTest {
|
||||
|
||||
@Test
|
||||
void includesUsageGuidanceInMcpMeta() {
|
||||
ToolMetadata metadata = new ToolMetadata();
|
||||
metadata.setWhenToUse("사용 시점");
|
||||
metadata.setWhenNotToUse("사용 제외");
|
||||
metadata.setIoLimits("입출력 제한");
|
||||
|
||||
assertThat(ToolMetadataMcpMapper.meta(metadata)).containsEntry("when_to_use", "사용 시점")
|
||||
.containsEntry("when_not_to_use", "사용 제외")
|
||||
.containsEntry("io_limits", "입출력 제한");
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,9 @@ import static org.mockito.Mockito.when;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.shinhanlife.dap.lib.annotation.GrowToolHint;
|
||||
import io.shinhanlife.dap.lib.config.McpProperties;
|
||||
import io.shinhanlife.dap.lib.metadata.ToolDefinition;
|
||||
import io.shinhanlife.dap.lib.metadata.ToolDefinitionRepository;
|
||||
import io.shinhanlife.dap.lib.metadata.ToolDescription;
|
||||
import io.shinhanlife.dap.lib.util.ToolSchemaResolver;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
@@ -34,6 +37,30 @@ class ToolRegistryHeartbeatSenderTest {
|
||||
assertThat(registeredTools(sender)).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void keepsOnlyFunctionDescriptionAndStoresUsageGuidanceSeparately() throws Exception {
|
||||
ApplicationContext applicationContext = mock(ApplicationContext.class);
|
||||
when(applicationContext.getBeansOfType(Object.class)).thenReturn(Map.of("tool", new EnabledTool()));
|
||||
ToolDefinitionRepository definitions = mock(ToolDefinitionRepository.class);
|
||||
when(definitions.findByName("test_enabled_tool")).thenReturn(java.util.Optional.of(new ToolDefinition(
|
||||
"test_enabled_tool", "테스트 도구", "1.0.0", "test",
|
||||
new ToolDescription("기능 설명", "사용 시점", "사용 제외", "입출력 제한"),
|
||||
"도구 설명", List.of("질문 1", "질문 2", "질문 3"), true, false, true,
|
||||
Map.of("type", "object", "properties", Map.of(), "additionalProperties", false), null,
|
||||
List.of("test"), null, List.of(), "MCP_TOOL")));
|
||||
ToolRegistryHeartbeatSender sender = new ToolRegistryHeartbeatSender(applicationContext, new ObjectMapper(),
|
||||
new McpProperties(), mock(ToolSchemaResolver.class), definitions);
|
||||
|
||||
sender.init();
|
||||
|
||||
assertThat(sender.getAllScannedTools()).singleElement().satisfies(tool -> {
|
||||
assertThat(tool.getDescription()).isEqualTo("기능 설명");
|
||||
assertThat(tool.getWhenToUse()).isEqualTo("사용 시점");
|
||||
assertThat(tool.getWhenNotToUse()).isEqualTo("사용 제외");
|
||||
assertThat(tool.getIoLimits()).isEqualTo("입출력 제한");
|
||||
});
|
||||
}
|
||||
|
||||
private void setField(Object target, String name, Object value) throws Exception {
|
||||
Field field = target.getClass().getDeclaredField(name);
|
||||
field.setAccessible(true);
|
||||
@@ -53,4 +80,10 @@ class ToolRegistryHeartbeatSenderTest {
|
||||
void execute() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class EnabledTool {
|
||||
@McpTool(name = "test_enabled_tool")
|
||||
void execute() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user