diff --git a/com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/lsp/protocol/CopilotAgentSettings.java b/com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/lsp/protocol/CopilotAgentSettings.java index 818fbd36..2879e0c0 100644 --- a/com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/lsp/protocol/CopilotAgentSettings.java +++ b/com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/lsp/protocol/CopilotAgentSettings.java @@ -3,6 +3,7 @@ package com.microsoft.copilot.eclipse.core.lsp.protocol; +import java.util.List; import java.util.Map; import java.util.Objects; @@ -37,6 +38,7 @@ public class CopilotAgentSettings { public static class ToolsSettings { private TerminalSettings terminal; private EditSettings edit; + private McpSettings mcp = new McpSettings(); /** Gets terminal settings, creating if needed. */ public TerminalSettings getTerminal() { @@ -54,9 +56,17 @@ public EditSettings getEdit() { return edit; } + /** Gets MCP settings, creating if needed. */ + public McpSettings getMcp() { + if (mcp == null) { + mcp = new McpSettings(); + } + return mcp; + } + @Override public int hashCode() { - return Objects.hash(terminal, edit); + return Objects.hash(terminal, edit, mcp); } @Override @@ -68,7 +78,8 @@ public boolean equals(Object obj) { return false; } ToolsSettings other = (ToolsSettings) obj; - return Objects.equals(terminal, other.terminal) && Objects.equals(edit, other.edit); + return Objects.equals(terminal, other.terminal) && Objects.equals(edit, other.edit) + && Objects.equals(mcp, other.mcp); } @Override @@ -76,10 +87,51 @@ public String toString() { return new ToStringBuilder(this) .append("terminal", terminal) .append("edit", edit) + .append("mcp", mcp) .toString(); } } + /** MCP auto-approve settings expected by CLS. */ + public static class McpSettings { + private List autoApprove = List.of(); + + public List getAutoApprove() { + return autoApprove; + } + + public void setAutoApprove(List autoApprove) { + this.autoApprove = autoApprove; + } + + @Override + public int hashCode() { + return Objects.hash(autoApprove); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + return Objects.equals(autoApprove, ((McpSettings) obj).autoApprove); + } + + @Override + public String toString() { + return new ToStringBuilder(this) + .append("autoApprove", autoApprove) + .toString(); + } + } + + /** MCP server/tool auto-approve entry expected by CLS. */ + public record McpAutoApproveConfig(String serverName, boolean isServerAllowed, List allowedTools) { + } + /** Terminal auto-approve rules: command/pattern -> allow(true)/deny(false). */ public static class TerminalSettings { private Map autoApprove; diff --git a/com.microsoft.copilot.eclipse.ui.test/src/com/microsoft/copilot/eclipse/ui/preferences/LanguageServerSettingManagerTests.java b/com.microsoft.copilot.eclipse.ui.test/src/com/microsoft/copilot/eclipse/ui/preferences/LanguageServerSettingManagerTests.java index 8cf28098..d1344725 100644 --- a/com.microsoft.copilot.eclipse.ui.test/src/com/microsoft/copilot/eclipse/ui/preferences/LanguageServerSettingManagerTests.java +++ b/com.microsoft.copilot.eclipse.ui.test/src/com/microsoft/copilot/eclipse/ui/preferences/LanguageServerSettingManagerTests.java @@ -7,6 +7,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.timeout; @@ -16,6 +17,7 @@ import java.util.LinkedHashMap; +import com.google.gson.JsonObject; import org.eclipse.core.net.proxy.IProxyData; import org.eclipse.core.net.proxy.IProxyService; import org.eclipse.jface.preference.IPreferenceStore; @@ -32,6 +34,7 @@ import com.microsoft.copilot.eclipse.core.lsp.CopilotLanguageServerConnection; import com.microsoft.copilot.eclipse.core.lsp.protocol.CopilotLanguageServerSettings; import com.microsoft.copilot.eclipse.core.lsp.protocol.CopilotLanguageServerSettings.CopilotSettings; +import com.microsoft.copilot.eclipse.core.utils.GsonUtils; import com.microsoft.copilot.eclipse.core.utils.PlatformUtils; import com.microsoft.copilot.eclipse.ui.CopilotUi; import com.microsoft.copilot.eclipse.ui.utils.PreferencesUtils; @@ -75,6 +78,29 @@ void testNoProxy() { verify(mockLsConnection, times(1)).updateConfig(params); } + @Test + void testSyncConfigurationIncludesEmptyMcpAutoApproveList() { + when(mockPreferenceStore.getBoolean(Constants.AUTO_SHOW_COMPLETION)).thenReturn(true); + + LanguageServerSettingManager manager = new LanguageServerSettingManager(mockLsConnection, mockProxyService, + mockPreferenceStore); + manager.syncConfiguration(); + + ArgumentCaptor paramsCaptor = ArgumentCaptor + .forClass(DidChangeConfigurationParams.class); + verify(mockLsConnection).updateConfig(paramsCaptor.capture()); + + JsonObject serializedSettings = GsonUtils.getDefault().toJsonTree(paramsCaptor.getValue().getSettings()) + .getAsJsonObject(); + assertTrue(serializedSettings.getAsJsonObject("github") + .getAsJsonObject("copilot") + .getAsJsonObject("agent") + .getAsJsonObject("tools") + .getAsJsonObject("mcp") + .getAsJsonArray("autoApprove") + .isEmpty()); + } + @Test void testBasicProxy() { // basic proxy test