DTRC-32091 expose IDE MCP tools to ACP agents when no tool filter is configured

McpToolFilter.MaskBased.fromMaskList treated a null mask list the same as an empty/blank one and returned ProhibitAll. ACP agents without an explicit idea_mcp_allowed_tools / mcp.tool.filter resolve their session tool filter to null, so every IDE MCP tool (including the dotTrace analyze tools) was denied and the execute_tool router exposed nothing but itself.

This was latent until MCP tool-state filtering was unified to also apply the session filter in VIA_ROUTER mode; previously router mode hardcoded AllowAll, so the null->ProhibitAll mapping had no visible effect.

Treat a null mask (no filter configured) as AllowAll, matching the documented "null exposes all tools" contract, while keeping an explicitly empty/blank string as ProhibitAll. The fix lives in the shared community filter, so it covers both the AIA and AIR ACP paths.


(cherry picked from commit 1e55c1950ea1630b38061037df5321f01804f2e8)

NET-MR-18836


(cherry picked from commit 5249db4a775d13cd4bfcb386ced1474ec22800b3)

IJ-CR-216670

GitOrigin-RevId: 235b9d76ff51ababb12935aaa4cc35cef92b1471
This commit is contained in:
Herman Kirshin
2026-08-03 11:19:54 +00:00
committed by intellij-monorepo-bot
parent cf912bfb83
commit 74384c8110
2 changed files with 16 additions and 4 deletions
@@ -77,14 +77,19 @@ sealed interface McpToolFilter {
companion object {
/**
* Creates a MaskBased filter from a mask list string.
* Creates a tool filter from a mask list string.
*
* @param maskList comma-separated list of mask patterns with +/- prefixes
* @return a new MaskBased filter that denies all if maskList is empty, or AllowAll if null/blank
* @return [AllowAll] when [maskList] is `null` (no filter configured — expose all tools),
* [ProhibitAll] when it is an explicitly empty/blank string (deny all),
* otherwise a [MaskBased] filter built from the patterns.
*/
fun fromMaskList(maskList: String?): McpToolFilter {
if (maskList.isNullOrBlank()) {
return ProhibitAll // Empty mask = deny all
if (maskList == null) {
return AllowAll // No filter configured = expose all tools
}
if (maskList.isBlank()) {
return ProhibitAll // Explicitly empty mask = deny all
}
return MaskBased(maskList)
}
@@ -127,6 +127,13 @@ class McpToolFilterTest {
assertThat(filter.shouldInclude("read_file")).isFalse()
}
@Test
fun `MaskBased fromMaskList returns allow-all filter for null`() {
val filter = McpToolFilter.MaskBased.fromMaskList(null)
assertThat(filter).isInstanceOf(McpToolFilter.AllowAll::class.java)
}
@Test
fun `MaskBased fromMaskList returns prohibit-all filter for empty string`() {
val filter = McpToolFilter.MaskBased.fromMaskList("")