diff --git a/api/build.gradle b/api/build.gradle index e142ec96186..030eace5621 100644 --- a/api/build.gradle +++ b/api/build.gradle @@ -466,6 +466,7 @@ dependencies { ) ) + // Jackson 2 BuildUtils.addExternalDependency( project, new ExternalDependency( diff --git a/core/src/org/labkey/core/mpc/McpServiceImpl.java b/core/src/org/labkey/core/mpc/McpServiceImpl.java index 6b9a84c2d03..c79b8d64dd7 100644 --- a/core/src/org/labkey/core/mpc/McpServiceImpl.java +++ b/core/src/org/labkey/core/mpc/McpServiceImpl.java @@ -60,9 +60,15 @@ import org.springframework.ai.google.genai.text.GoogleGenAiTextEmbeddingModel; import org.springframework.ai.google.genai.text.GoogleGenAiTextEmbeddingOptions; import org.springframework.ai.mcp.McpToolUtils; +import org.springframework.ai.chat.model.ToolContext; import org.springframework.ai.tool.ToolCallback; +import org.springframework.ai.tool.definition.ToolDefinition; +import org.springframework.ai.tool.metadata.ToolMetadata; +import org.springframework.ai.document.Document; +import org.springframework.ai.vectorstore.SearchRequest; import org.springframework.ai.vectorstore.SimpleVectorStore; import org.springframework.ai.vectorstore.VectorStore; +import org.springframework.ai.vectorstore.filter.Filter; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import reactor.core.publisher.Mono; @@ -171,7 +177,7 @@ public boolean isReady() @Override public void registerTools(@NotNull List tools) { - tools.forEach(tool -> toolMap.put(tool.getToolDefinition().name(), tool)); + tools.forEach(tool -> toolMap.put(tool.getToolDefinition().name(), new _LoggingToolCallback(tool))); } @Override @@ -316,6 +322,65 @@ public void shutdownStarted() } } + + /** Delegating wrapper that logs vector store similarity searches */ + private static class _LoggingVectorStore implements VectorStore + { + private final VectorStore delegate; + + _LoggingVectorStore(VectorStore delegate) + { + this.delegate = delegate; + } + + @Override + public void add(List documents) + { + delegate.add(documents); + } + + @Override + public void delete(Filter.Expression filterExpression) + { + delegate.delete(filterExpression); + } + + @Override + public void delete(List idList) + { + delegate.delete(idList); + } + + @Override + public List similaritySearch(SearchRequest request) + { + LOG.info("Vector store search: query=\"{}\"", request.getQuery()); + List results = delegate.similaritySearch(request); + if (results.isEmpty()) + { + LOG.info("Vector store search returned no results"); + } + else + { + LOG.info("Vector store search returned {} result(s):", results.size()); + for (Document doc : results) + { + String content = doc.getText(); + String snippet = content.length() > 200 ? content.substring(0, 200) + "..." : content; + LOG.info(" - [{}] {}", doc.getMetadata(), snippet); + } + } + return results; + } + + @Override + public String getName() + { + return delegate.getName(); + } + } + + @Override public ChatClient getChat(HttpSession session, String agentName, Supplier systemPromptSupplier, boolean createIfNotExists) { @@ -352,7 +417,7 @@ private ChatClient createSpringChat(HttpSession session, String agentName, Suppl VectorStore vs = getVectorStore(); if (null != vs) - advisors.add(QuestionAnswerAdvisor.builder(vs).build()); + advisors.add(QuestionAnswerAdvisor.builder(new _LoggingVectorStore(vs)).build()); return ChatClient.builder(modelProvider.getChatModel()) .defaultOptions(modelProvider.getChatOptions()) @@ -558,11 +623,11 @@ class _GeminiProvider implements _ModelProvider @Override public String getModel() { - return "gemini-2.5-flash"; +// return "gemini-2.5-flash"; // gemini-2.5-flash // gemini-2.5-pro // gemini-3-flash-preview - // gemini-3-pro-preview + return "gemini-3-pro-preview"; } @Override @@ -630,6 +695,43 @@ public EmbeddingModel createEmbeddingModel() } + private static class _LoggingToolCallback implements ToolCallback + { + private final ToolCallback delegate; + + _LoggingToolCallback(ToolCallback delegate) + { + this.delegate = delegate; + } + + @Override + public ToolDefinition getToolDefinition() + { + return delegate.getToolDefinition(); + } + + @Override + public ToolMetadata getToolMetadata() + { + return delegate.getToolMetadata(); + } + + @Override + public String call(String toolInput) + { + LOG.info("MCP tool invoked: {}", delegate.getToolDefinition().name()); + return delegate.call(toolInput); + } + + @Override + public String call(String toolInput, ToolContext toolContext) + { + LOG.info("MCP tool invoked: {}", delegate.getToolDefinition().name()); + return delegate.call(toolInput, toolContext); + } + } + + class _ClaudeProvider implements _ModelProvider { @Override