Skip to content

[secops-mcp] Add FastMCP tool annotations (readOnlyHint, destructiveHint) for safety hints and execution confirmations #320

Description

@dandye

Problem Statement

Currently, all tools across server/secops/secops_mcp/tools/ are registered using unadorned @server.tool() decorators without tool metadata annotations.

Model Context Protocol (MCP) clients, autonomous agents, and orchestrators (e.g. Gemini CLI, ADK, Claude, Cursor) rely on standard ToolAnnotations hints to evaluate tool safety prior to execution. In particular:

  • readOnlyHint (boolean): Signals whether a tool only queries data without altering the state of the system.
  • destructiveHint (boolean): When readOnlyHint is False, indicates whether the operation deletes, overwrites, or invalidates resources versus performing an additive mutation.
  • idempotentHint (boolean): Signals whether repeated execution with identical arguments produces the same state.

Without these annotations, clients cannot distinguish harmless read-only telemetry queries (e.g. udm_search, list_rules, get_security_alert) from destructive operations (e.g. delete_rule, delete_feed, delete_data_table_row, delete_watchlist, archive_rule). This forces clients to either prompt the user for interactive confirmation on every single safe read query, or execute mutating and destructive actions without confirmation.


Requested Pattern

FastMCP supports passing annotations dictionaries directly to the @server.tool() decorator:

from fastmcp import FastMCP

mcp = FastMCP("Database Manager")

@mcp.tool(
    annotations={
        "readOnlyHint": False,
        "destructiveHint": True
    }
)
def drop_table(table_name: str) -> str:
    """Permanently deletes a database table."""
    # Your destructive logic here
    return f"Table {table_name} has been dropped."

When registered, FastMCP validates and parses these dictionaries into mcp.types.ToolAnnotations(readOnlyHint=False, destructiveHint=True).


Proposed Tool Classification for secops-mcp

1. Destructive Operations (readOnlyHint: False, destructiveHint: True)

Tools that permanently delete, archive, or deactivate resources, or invalidate credentials:

  • security_rules.py: delete_rule, archive_rule
  • feed_management.py: delete_feed, disable_feed, generate_feed_secret
  • data_table_management.py: delete_data_table_row
  • rule_exclusions.py: delete_rule_exclusion
  • watchlist_management.py: delete_watchlist
  • curated_rules_management.py: disable_curated_rule
  • parser_management.py: deactivate_parser
  • (If SOAR case tools are active): execute_bulk_close_case, close_case

2. Mutating / Additive Operations (readOnlyHint: False, destructiveHint: False)

Tools that create, update, or append state without permanently deleting data:

  • security_rules.py: create_rule, update_rule
  • feed_management.py: create_feed, update_feed, enable_feed
  • data_table_management.py: create_data_table, add_rows_to_data_table
  • reference_list_management.py: create_reference_list, update_reference_list
  • rule_exclusions.py: create_rule_exclusion, update_rule_exclusion
  • watchlist_management.py: create_watchlist, update_watchlist
  • curated_rules_management.py: enable_curated_rule
  • parser_management.py: create_parser, activate_parser
  • log_ingestion.py: ingest_log, batch_ingest_logs
  • security_alerts.py: update_security_alert
  • investigation_management.py: trigger_investigation

3. Read-Only Operations (readOnlyHint: True)

Queries, searches, and validation tools that do not mutate server state:

  • UDM & Events: udm_search, search_security_events, get_security_event
  • Rules & Detections: list_rules, get_rule, validate_rule, test_rule (validating and testing YARA-L 2.0 / YL2 rules against historical data)
  • Curated Rules: list_curated_rules, get_curated_rule, list_curated_rule_detections
  • Alerts: list_security_alerts, get_security_alert
  • Feeds: list_feeds, get_feed
  • Parsers: list_parsers, get_parser, run_parser
  • Data Tables & Reference Lists: list_data_tables, get_reference_list
  • Investigations: list_investigations, get_investigation
  • Threat Intel & Entities: search_threat_intel, lookup_entity, get_ioc_matches
  • Watchlists & Exclusions: list_watchlists, get_watchlist, list_rule_exclusions, get_rule_exclusion

Deliverables & Acceptance Criteria

  1. Update @server.tool() decorators across all tool modules in server/secops/secops_mcp/tools/ to include explicit annotations mappings (readOnlyHint, destructiveHint, and idempotentHint where applicable).
  2. Verify all tools exposed by server.run() surface ToolAnnotations during MCP tools/list protocol negotiation.
  3. Update unit tests in server/secops/tests/ to assert that all registered tools define annotations and verify expected hint values.
  4. Ensure all existing tests in server/secops/tests/ continue to pass.

Activity

  1. added
    enhancementNew feature or request
    pythonPull requests that update python code
    on Sep 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestpythonPull requests that update python code

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions