fix(core): ensure policy engine compatibility with isolated MCP servers

This commit addresses PR feedback regarding the prefixing of isolated subagent MCP servers and its potential to break existing security policies relying on standard FQNs.

1. Added `originalName` to `MCPServerConfig` and `originalServerName` to `DiscoveredMCPTool`.
2. Updated `CoreToolScheduler` to reconstruct the original FQN (without the `__agent__` prefix) when performing policy checks via the Policy Engine. This ensures policies mapping to standard `mcp_{server}_{tool}` formats still apply correctly to isolated agents.
3. Added a remote agent back to `NewAgentsNotification.test.tsx` to maintain coverage for both local and remote agents.
This commit is contained in:
Akhilesh Kumar
2026-03-13 17:30:32 +00:00
parent 3bf0a5579a
commit ee425228fe
7 changed files with 32 additions and 3 deletions
@@ -38,6 +38,13 @@ describe('NewAgentsNotification', () => {
},
},
},
{
name: 'Agent C',
description: 'Description C',
kind: 'remote' as const,
agentCardUrl: '',
inputConfig: { inputSchema: {} },
},
];
const onSelect = vi.fn();
@@ -11,6 +11,7 @@ exports[`NewAgentsNotification > renders agent list 1`] = `
│ │ - Agent A: Description A │ │
│ │ - Agent B: Description B │ │
│ │ (Includes MCP servers: github, postgres) │ │
│ │ - Agent C: Description C │ │
│ │ │ │
│ └────────────────────────────────────────────────────────────────────────────────────────────┘ │
│ │
+6
View File
@@ -550,6 +550,12 @@ export function markdownToAgentDefinition(
config.description,
config.include_tools,
config.exclude_tools,
undefined, // extension
undefined, // oauth
undefined, // authProviderType
undefined, // targetAudience
undefined, // targetServiceAccount
name, // originalName
);
}
}
+5
View File
@@ -445,6 +445,11 @@ export class MCPServerConfig {
readonly targetAudience?: string,
/* targetServiceAccount format: <service-account-name>@<project-num>.iam.gserviceaccount.com */
readonly targetServiceAccount?: string,
/**
* The original name of the server before any prefixing (e.g. for subagents).
* This is used by the policy engine to match rules.
*/
readonly originalName?: string,
) {}
}
+11 -3
View File
@@ -47,7 +47,11 @@ import {
type ToolCallResponseInfo,
} from '../scheduler/types.js';
import { ToolExecutor } from '../scheduler/tool-executor.js';
import { DiscoveredMCPTool } from '../tools/mcp-tool.js';
import {
DiscoveredMCPTool,
MCP_TOOL_PREFIX,
MCP_QUALIFIED_NAME_SEPARATOR,
} from '../tools/mcp-tool.js';
import { getPolicyDenialError } from '../scheduler/policy.js';
import { GeminiCliOperation } from '../telemetry/constants.js';
@@ -638,12 +642,16 @@ export class CoreToolScheduler {
// Policy Check using PolicyEngine
// We must reconstruct the FunctionCall format expected by PolicyEngine
const toolCallForPolicy = {
name: toolCall.request.name,
name:
toolCall.tool instanceof DiscoveredMCPTool &&
toolCall.tool.originalServerName
? `${MCP_TOOL_PREFIX}${toolCall.tool.originalServerName}${MCP_QUALIFIED_NAME_SEPARATOR}${toolCall.tool.serverToolName}`
: toolCall.request.name,
args: toolCall.request.args,
};
const serverName =
toolCall.tool instanceof DiscoveredMCPTool
? toolCall.tool.serverName
? (toolCall.tool.originalServerName ?? toolCall.tool.serverName)
: undefined;
const toolAnnotations = toolCall.tool.toolAnnotations;
+1
View File
@@ -1266,6 +1266,7 @@ export async function discoverTools(
mcpServerConfig.extension?.name,
mcpServerConfig.extension?.id,
annotations as Record<string, unknown> | undefined,
mcpServerConfig.originalName,
);
discoveredTools.push(tool);
+1
View File
@@ -348,6 +348,7 @@ export class DiscoveredMCPTool extends BaseDeclarativeTool<
override readonly extensionName?: string,
override readonly extensionId?: string,
private readonly _toolAnnotations?: Record<string, unknown>,
readonly originalServerName?: string,
) {
super(
nameOverride ??