Skip to content

feat(core): support tool annotations and global wildcards in policies - #19671

Closed
Sikandar1310291 wants to merge 1 commit into
google-gemini:mainfrom
Sikandar1310291:feat/policy-engine-enhancements
Closed

feat(core): support tool annotations and global wildcards in policies#19671
Sikandar1310291 wants to merge 1 commit into
google-gemini:mainfrom
Sikandar1310291:feat/policy-engine-enhancements

Conversation

@Sikandar1310291

Copy link
Copy Markdown

Description

This PR enhances the Policy Engine to support:

  1. Global MCP Wildcards: Use mcpName = "*" in rules to target all tools from any MCP server.
  2. Tool Annotation Matching: Match tools based on semantic annotations like readOnlyHint.
  3. Plan Mode Rule Migration: Hardcoded read-only logic in mcp-client.ts has been migrated to plan.toml using the new annotation matching mechanism.

Changes

  • Updated PolicyRule and SafetyCheckerRule types.
  • Enhanced PolicyEngine matching logic for wildcards and annotations.
  • Updated CoreToolScheduler to propagate tool annotations.
  • Refined wildcard matching to ensure mcpName = "*" only targets MCP tools.
  • Migrated hardcoded rules to plan.toml.

Verification

  • Added specialized tests in policy-engine-annotations.test.ts.
  • All 92 existing policy tests passed.
  • Verified system stability with full core test suite.

@Sikandar1310291
Sikandar1310291 requested review from a team as code owners February 20, 2026 18:18
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @Sikandar1310291, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the policy engine's flexibility and configurability by introducing support for global wildcards and tool annotations. These additions allow for more dynamic and expressive policy definitions, particularly for managing tool access across multiple Model Context Protocol (MCP) servers and for applying rules based on intrinsic tool properties. The change also streamlines policy management by migrating previously hardcoded logic into declarative TOML configuration.

Highlights

  • Global MCP Wildcards: Implemented support for global MCP wildcards (mcpName = "*") in policy rules, allowing policies to apply to all tools from any MCP server.
  • Tool Annotation Matching: Introduced tool annotation matching, enabling policy rules to target tools based on semantic annotations like readOnlyHint.
  • Plan Mode Rule Migration: Migrated the hardcoded read-only logic for MCP tools in "Plan" mode to a configurable rule in plan.toml, leveraging the new annotation matching.
  • Policy Engine Enhancements: Updated PolicyRule and SafetyCheckerRule types to include an optional toolAnnotations field, and enhanced the PolicyEngine's matching logic to correctly interpret global MCP wildcards and evaluate tool annotations.
  • Tool Annotation Propagation: Modified CoreToolScheduler to extract and propagate tool annotations to the PolicyEngine during policy checks.
  • New Test Coverage: Added new dedicated tests (policy-engine-annotations.test.ts) to thoroughly verify the functionality of global wildcards and tool annotation matching.
Changelog
  • package-lock.json
    • Added "peer": true to several dependency entries.
  • packages/core/src/core/coreToolScheduler.ts
    • Modified the check method call to the PolicyEngine to pass extracted toolAnnotations.
    • Added logic to populate toolAnnotations with readOnlyHint: true if toolCall.tool.isReadOnly is true.
  • packages/core/src/policy/policies/plan.toml
    • Added a new policy rule that allows all MCP tools (mcpName = "*") with readOnlyHint = true when in "plan" mode.
  • packages/core/src/policy/policy-engine-annotations.test.ts
    • Added a new test suite to validate the PolicyEngine's handling of global MCP wildcards and tool annotation matching.
  • packages/core/src/policy/policy-engine.ts
    • Updated matchesWildcard to ensure that a global wildcard (*) for mcpName only matches tool names containing __, indicating an MCP tool.
    • Modified ruleMatches to incorporate toolAnnotations into the matching logic, requiring all specified rule annotations to be present and match in the tool's annotations.
    • Adjusted the check method signature to accept toolAnnotations and passed them to ruleMatches.
  • packages/core/src/policy/toml-loader.ts
    • Extended PolicyRuleSchema and SafetyCheckerRuleSchema to include an optional toolAnnotations field.
    • Updated loadPoliciesFromToml to correctly parse and assign toolAnnotations from TOML files to PolicyRule and SafetyCheckerRule objects.
  • packages/core/src/policy/types.ts
    • Added an optional toolAnnotations property to the PolicyRule and SafetyCheckerRule interfaces.
  • packages/core/src/tools/mcp-client.ts
    • Removed the previous hardcoded logic that dynamically added a policy rule for read-only MCP tools in "Plan" mode, as this is now handled declaratively in plan.toml.
Activity
  • Specialized tests were added in policy-engine-annotations.test.ts to cover the new wildcard and annotation matching features.
  • All 92 existing policy tests passed, indicating no regressions.
  • System stability was verified with the full core test suite.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-cli gemini-cli Bot added the status/need-issue Pull requests that need to have an associated issue. label Feb 20, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces valuable enhancements to the policy engine by adding support for global MCP wildcards and tool annotations, refactoring hardcoded logic into configurable policies. However, critical security vulnerabilities have been identified in the implementation of tool annotation matching and wildcard policy enforcement. These issues include incomplete and inconsistent propagation of tool annotations (where only readOnlyHint is handled and MessageBus is not updated), and a flaw in server-specific wildcard matching that could lead to unintended tool executions. These need to be addressed to ensure the reliability and consistency of the access control system.

Comment on lines +68 to 74
if (prefix === '*') {
if (serverName === undefined) {
return false;
}
} else if (serverName !== undefined && serverName !== prefix) {
return false;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The current logic for handling server-specific wildcards (e.g., my-server__*) is not strict enough. If a non-MCP tool is named with a __ separator (e.g., my-server__foo), it can incorrectly match a policy intended for an MCP tool from my-server. This happens because when serverName is undefined, the else if condition is not met, and the check falls through.

This could lead to unintended tool executions if a permissive policy is set for a specific MCP server. The check should be simplified to ensure that for any non-global wildcard, the serverName must be defined and must match the rule's prefix.

Suggested change
if (prefix === '*') {
if (serverName === undefined) {
return false;
}
} else if (serverName !== undefined && serverName !== prefix) {
return false;
}
if (prefix === '*') {
// For a global MCP wildcard, this rule should only match if it's an MCP call.
if (serverName === undefined) {
return false;
}
} else if (serverName !== prefix) {
// For a specific server wildcard (e.g., "my-server__*"), the serverName
// must be defined and must match the prefix. This prevents a non-MCP
// tool from matching a rule intended for a specific MCP server.
return false;
}

Comment on lines +629 to +636
const toolAnnotations: Record<string, unknown> = {};
if (toolCall.tool.isReadOnly) {
toolAnnotations['readOnlyHint'] = true;
}

const { decision, rule } = await this.config
.getPolicyEngine()
.check(toolCallForPolicy, serverName);
.check(toolCallForPolicy, serverName, toolAnnotations);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

Incomplete Tool Annotation Propagation

The implementation of tool annotation matching is incomplete. Here, the toolAnnotations object is manually populated with only the readOnlyHint annotation. Any other annotations provided by MCP servers or defined in policy rules are ignored. This means rules intended to restrict tools based on other semantic annotations (e.g., a rule to deny tools with a "dangerous" annotation) will never match, as those annotations are never passed to the policy engine.

Remediation:

  • Update the AnyDeclarativeTool interface and DiscoveredMCPTool to store and expose all available tool annotations.
  • Update this scheduler to collect and propagate all annotations from the tool instance to the PolicyEngine.

Comment on lines 321 to 325
async check(
toolCall: FunctionCall,
serverName: string | undefined,
toolAnnotations?: Record<string, unknown>,
): Promise<CheckResult> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

Inconsistent Policy Enforcement via MessageBus

The check method now requires toolAnnotations for correct policy matching, but existing callers like the MessageBus (in packages/core/src/confirmation-bus/message-bus.ts) have not been updated to provide this context. Consequently, any policy rules relying on annotations will fail to match during checks initiated via the MessageBus (e.g., when tools check their own permissions). This leads to inconsistent security decisions where a tool might be allowed by the scheduler but denied when the tool itself checks its permissions.

Remediation:

  • Update the MessageBus protocol and the ToolConfirmationRequest message to include toolAnnotations.
  • Ensure all callers of PolicyEngine.check provide the full set of tool annotations.

@gemini-cli

gemini-cli Bot commented Feb 21, 2026

Copy link
Copy Markdown
Contributor

Hi there! Thank you for your contribution to Gemini CLI.

To improve our contribution process and better track changes, we now require all pull requests to be associated with an existing issue, as announced in our recent discussion and as detailed in our CONTRIBUTING.md.

This pull request is being closed because it is not currently linked to an issue. Once you have updated the description of this PR to link an issue (e.g., by adding Fixes #123 or Related to #123), it will be automatically reopened.

How to link an issue:
Add a keyword followed by the issue number (e.g., Fixes #123) in the description of your pull request. For more details on supported keywords and how linking works, please refer to the GitHub Documentation on linking pull requests to issues.

Thank you for your understanding and for being a part of our community!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/l A large sized PR status/need-issue Pull requests that need to have an associated issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants