mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
RIDER-140018 [rider-mcp]: apply MCP product filters in tools settings
The settings configurable needs to show the tools that are actually available for the product while still letting users edit their own MCP tool filters. Apply MCP tool filter providers when rebuilding settings groups, excluding only the settings-backed providers that would otherwise filter the configurable by its own persisted state. This keeps Rider-specific replacements such as rename_refactoring hidden from the settings list while preserving user control over the exposed tools. Settings-backed providers are marked with the UserConfigurableMcpToolFilterProvider marker interface instead of hard-coding their classes in the configurable. RIDER-140018 fix IJ-MR-214874 GitOrigin-RevId: 4214c5aa340cd19d09d87830ebe76057e43e65f7
This commit is contained in:
committed by
intellij-monorepo-bot
parent
3bed40366f
commit
09a095f714
+1
-1
@@ -9,7 +9,7 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
internal class DisallowListBasedMcpToolFilterProvider : McpToolFilterProvider {
|
||||
internal class DisallowListBasedMcpToolFilterProvider : UserConfigurableMcpToolFilterProvider {
|
||||
override fun applyFilters(context: McpToolFilterContext, clientInfo: Implementation?, sessionOptions: McpServerService.McpSessionOptions?, invocationMode: McpToolInvocationMode) {
|
||||
val settings = McpToolDisallowListSettings.getInstance()
|
||||
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
internal class SettingsBasedMcpToolFilterProvider : McpToolFilterProvider {
|
||||
internal class SettingsBasedMcpToolFilterProvider : UserConfigurableMcpToolFilterProvider {
|
||||
override fun applyFilters(context: McpToolFilterContext, clientInfo: Implementation?, sessionOptions: McpServerService.McpSessionOptions?, invocationMode: McpToolInvocationMode) {
|
||||
val settings = McpToolFilterSettings.getInstance()
|
||||
applyMaskFilter(context, settings.toolsFilter)
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.mcpserver.impl
|
||||
|
||||
import com.intellij.mcpserver.McpToolFilterProvider
|
||||
|
||||
/**
|
||||
* Marker for [McpToolFilterProvider]s whose filtering reflects the user-editable settings managed by the MCP tools
|
||||
* settings UI ([com.intellij.mcpserver.settings.McpToolFilterConfigurable]).
|
||||
*
|
||||
* The configurable excludes such providers when building its tool list, so that the list shows every tool available
|
||||
* in the product instead of being filtered by the configurable's own persisted state.
|
||||
*/
|
||||
internal interface UserConfigurableMcpToolFilterProvider : McpToolFilterProvider
|
||||
@@ -8,6 +8,7 @@ import com.intellij.mcpserver.McpTool
|
||||
import com.intellij.mcpserver.McpToolCategory
|
||||
import com.intellij.mcpserver.McpToolsMarkdownExporter
|
||||
import com.intellij.mcpserver.impl.McpServerService
|
||||
import com.intellij.mcpserver.impl.UserConfigurableMcpToolFilterProvider
|
||||
import com.intellij.mcpserver.toolsets.general.UniversalToolset
|
||||
import com.intellij.mcpserver.settings.McpToolDisallowListSettings.ToolState
|
||||
import com.intellij.openapi.fileChooser.FileChooserFactory
|
||||
@@ -464,8 +465,7 @@ class McpToolFilterConfigurable : SearchableConfigurable {
|
||||
emptyStateLabel = null
|
||||
|
||||
allTools = McpServerService.getInstance().getMcpToolsFiltered(
|
||||
useFiltersFromEP = false,
|
||||
excludeProviders = emptySet(),
|
||||
excludeProviders = setOf(UserConfigurableMcpToolFilterProvider::class.java),
|
||||
)
|
||||
initialToolStates = normalizeToolStateKeys(initialToolStates)
|
||||
val normalizedToolStates = normalizeToolStateKeys(allToolStates)
|
||||
|
||||
+69
-2
@@ -1,17 +1,26 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.mcpserver.settings
|
||||
|
||||
import com.intellij.mcpserver.McpSessionInvocationMode
|
||||
import com.intellij.mcpserver.McpTool
|
||||
import com.intellij.mcpserver.McpToolCallResult
|
||||
import com.intellij.mcpserver.McpToolCategory
|
||||
import com.intellij.mcpserver.McpToolDescriptor
|
||||
import com.intellij.mcpserver.McpToolFilterProvider
|
||||
import com.intellij.mcpserver.McpToolInvocationMode
|
||||
import com.intellij.mcpserver.McpToolSchema
|
||||
import com.intellij.mcpserver.McpSessionInvocationMode
|
||||
import com.intellij.mcpserver.impl.McpServerService
|
||||
import com.intellij.mcpserver.settings.McpToolDisallowListSettings.ToolState
|
||||
import com.intellij.mcpserver.toolsets.general.UniversalToolset
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.testFramework.ExtensionTestUtil
|
||||
import com.intellij.testFramework.junit5.TestApplication
|
||||
import com.intellij.ui.components.JBCheckBox
|
||||
import com.intellij.util.ui.ThreeStateCheckBox
|
||||
import com.intellij.testFramework.junit5.TestApplication
|
||||
import io.modelcontextprotocol.kotlin.sdk.types.Implementation
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.buildJsonObject
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
@@ -146,6 +155,35 @@ class McpToolFilterConfigurableTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `configurable applies product filter providers but ignores user settings filters`() {
|
||||
val disposable = Disposer.newDisposable()
|
||||
val filteredTool = McpServerService.getInstance()
|
||||
.getMcpToolsFiltered(useFiltersFromEP = false, excludeProviders = emptySet())
|
||||
.first { it.descriptor.name != UniversalToolset::execute_tool.name }
|
||||
val filteredToolName = filteredTool.descriptor.fullyQualifiedName
|
||||
val configurable = McpToolFilterConfigurable()
|
||||
|
||||
try {
|
||||
McpToolFilterSettings.getInstance().toolsFilter = "-*"
|
||||
ExtensionTestUtil.addExtensions(
|
||||
McpToolFilterProvider.EP,
|
||||
listOf(disableToolFilterProvider(filteredToolName)),
|
||||
disposable,
|
||||
)
|
||||
configurable.createComponent()
|
||||
|
||||
val configurableToolNames = configurableTools(configurable).map { it.descriptor.fullyQualifiedName }
|
||||
assertThat(configurableToolNames)
|
||||
.doesNotContain(filteredToolName)
|
||||
.isNotEmpty()
|
||||
}
|
||||
finally {
|
||||
configurable.disposeUIResources()
|
||||
Disposer.dispose(disposable)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `category on demand state ignores disabled tools`() {
|
||||
val configurable = McpToolFilterConfigurable()
|
||||
@@ -230,6 +268,13 @@ class McpToolFilterConfigurableTest {
|
||||
return method.invoke(configurable, tools) as ThreeStateCheckBox.State
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private fun configurableTools(configurable: McpToolFilterConfigurable): List<McpTool> {
|
||||
val field = McpToolFilterConfigurable::class.java.getDeclaredField("allTools")
|
||||
field.isAccessible = true
|
||||
return field.get(configurable) as List<McpTool>
|
||||
}
|
||||
|
||||
private fun testTool(name: String, fullyQualifiedName: String): McpTool {
|
||||
return object : McpTool {
|
||||
override val descriptor: McpToolDescriptor = McpToolDescriptor(
|
||||
@@ -249,4 +294,26 @@ class McpToolFilterConfigurableTest {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun disableToolFilterProvider(toolName: String): McpToolFilterProvider {
|
||||
return object : McpToolFilterProvider {
|
||||
override fun applyFilters(
|
||||
context: McpToolFilterProvider.McpToolFilterContext,
|
||||
clientInfo: Implementation?,
|
||||
sessionOptions: McpServerService.McpSessionOptions?,
|
||||
invocationMode: McpToolInvocationMode,
|
||||
) {
|
||||
context.updateState(enabled = false) { tool -> tool.descriptor.fullyQualifiedName == toolName }
|
||||
}
|
||||
|
||||
override fun getUpdates(
|
||||
clientInfo: Implementation?,
|
||||
scope: CoroutineScope,
|
||||
sessionOptions: McpServerService.McpSessionOptions?,
|
||||
invocationMode: McpToolInvocationMode,
|
||||
): Flow<Unit> {
|
||||
return emptyFlow()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user