From 4a7aba5b081d17cd0b31deb82037546490fbbda9 Mon Sep 17 00:00:00 2001 From: labkey-nicka Date: Thu, 2 Jul 2026 16:30:27 -0700 Subject: [PATCH 1/3] McpService.isAIFeaturesEnabled --- api/src/org/labkey/api/mcp/AbstractAgentAction.java | 9 +++++++++ api/src/org/labkey/api/mcp/McpService.java | 6 ++++++ api/src/org/labkey/api/mcp/NoopMcpService.java | 6 ++++++ api/src/org/labkey/api/util/PageFlowUtil.java | 2 +- devtools/src/org/labkey/devtools/view/chat.jsp | 6 +----- query/src/org/labkey/query/view/sourceQuery.jsp | 2 +- 6 files changed, 24 insertions(+), 7 deletions(-) diff --git a/api/src/org/labkey/api/mcp/AbstractAgentAction.java b/api/src/org/labkey/api/mcp/AbstractAgentAction.java index 0affd4c5517..a8bb158aab1 100644 --- a/api/src/org/labkey/api/mcp/AbstractAgentAction.java +++ b/api/src/org/labkey/api/mcp/AbstractAgentAction.java @@ -85,9 +85,18 @@ protected String handleEscape(String prompt) @Override public void validateForm(F form, Errors errors) { + if (!McpService.get().isAIFeaturesEnabled()) + { + errors.reject(ERROR_GENERIC, "Agent actions are not available."); + return; + } + String prompt = form.getPrompt(); if (prompt != null && prompt.length() > MAX_PROMPT_CHAR_LENGTH) + { errors.rejectValue("prompt", ERROR_GENERIC, "Prompt cannot exceed " + MAX_PROMPT_CHAR_LENGTH + " characters."); + return; + } // Only honor a client-supplied conversationId if this agent previously issued this session that // id. Otherwise, generate a fresh one. This prevents a same-session caller from splicing into diff --git a/api/src/org/labkey/api/mcp/McpService.java b/api/src/org/labkey/api/mcp/McpService.java index 4717e859b78..2cf82aeedec 100644 --- a/api/src/org/labkey/api/mcp/McpService.java +++ b/api/src/org/labkey/api/mcp/McpService.java @@ -99,6 +99,7 @@ public interface McpService extends ToolCallbackProvider Logger LOG = LogHelper.getLogger(McpService.class, "MCP registration exceptions"); String ENABLE_MCP_SERVER_FLAG = "enableMcpServer"; + String ENABLE_AI_FEATURES = "enableAIFeatures"; // Interface for MCP classes that we will "ingest" using Spring annotations. Provides a few helper methods. interface McpImpl @@ -145,6 +146,11 @@ default boolean isEnabled() return OptionalFeatureService.get().isFeatureEnabled(ENABLE_MCP_SERVER_FLAG); } + default boolean isAIFeaturesEnabled() + { + return OptionalFeatureService.get().isFeatureEnabled(ENABLE_AI_FEATURES); + } + boolean isReady(); // Register MCPs in Module.startup() diff --git a/api/src/org/labkey/api/mcp/NoopMcpService.java b/api/src/org/labkey/api/mcp/NoopMcpService.java index 2a0ff1c2f9a..1923c770ccd 100644 --- a/api/src/org/labkey/api/mcp/NoopMcpService.java +++ b/api/src/org/labkey/api/mcp/NoopMcpService.java @@ -42,6 +42,12 @@ public boolean isEnabled() return false; } + @Override + public boolean isAIFeaturesEnabled() + { + return false; + } + @Override public boolean isReady() { diff --git a/api/src/org/labkey/api/util/PageFlowUtil.java b/api/src/org/labkey/api/util/PageFlowUtil.java index 520a6c2d171..bfd62f4fb58 100644 --- a/api/src/org/labkey/api/util/PageFlowUtil.java +++ b/api/src/org/labkey/api/util/PageFlowUtil.java @@ -2265,7 +2265,7 @@ public static JSONObject jsInitObject(ContainerUser context, @Nullable PageConfi if (AppProps.getInstance().isOptionalFeatureEnabled(NotificationMenuView.EXPERIMENTAL_NOTIFICATION_MENU) && user != null) json.put("notifications", Map.of("unreadCount", NotificationService.get().getUnreadNotificationCountByUser(null, user.getUserId()))); - if (McpService.get().isEnabled()) + if (McpService.get().isAIFeaturesEnabled()) json.put("mcpReady", McpService.get().isReady()); JSONObject defaultHeaders = new JSONObject(); diff --git a/devtools/src/org/labkey/devtools/view/chat.jsp b/devtools/src/org/labkey/devtools/view/chat.jsp index 2799776390d..19b8defd8e5 100644 --- a/devtools/src/org/labkey/devtools/view/chat.jsp +++ b/devtools/src/org/labkey/devtools/view/chat.jsp @@ -15,10 +15,6 @@ * limitations under the License. */ %> -<%@ page import="org.labkey.api.util.DOM" %> -<%@ page import="java.util.stream.Stream" %> -<%@ page import="static org.labkey.api.util.DOM.*" %> -<%@ page import="static org.labkey.api.util.DOM.Attribute.*" %> <%@ page extends="org.labkey.api.jsp.JspBase" %> <%@ taglib prefix="labkey" uri="http://www.labkey.org/taglib" %>