Skip to content

Add an alert investigation example with VirusTotal MCP - #1426

Open
bernardoquintero wants to merge 3 commits into
google-gemini:mainfrom
bernardoquintero:examples/virustotal-mcp
Open

bernardoquintero wants to merge 3 commits into
google-gemini:mainfrom
bernardoquintero:examples/virustotal-mcp

Conversation

@bernardoquintero

@bernardoquintero bernardoquintero commented Oct 14, 2026 •

Copy link
Copy Markdown

Demonstrates alert investigation with the Antigravity managed agent, the Interactions API and VirusTotal MCP. The example restricts access to one domain-report tool, checks generated evidence against the actual tool result, and separates facts, inference and unresolved questions.

It uses Colab Secrets, records the interaction ID for recovery, prevents duplicate creation, and cleans up its own sandbox. It also documents credential revocation and clearing outputs before sharing, and adds the notebook to the examples index.

Validation:

  • Repository notebook format and lint checks, plus offline lifecycle and transport tests.
  • Native Colab with google-genai 2.30.1: completed interaction, exactly one get_domain_report call for example.com, matching evidence, and confirmed sandbox cleanup.

The Colab install reported a dependency conflict: google-colab pins google-auth 2.49.0, while google-genai 2.30.1 requires >=2.56.0,<3.0.0. The tested Colab Secrets and notebook flow completed with google-auth 2.62.0; other Colab features were not tested.

Run the tested notebook in Colab.

Related to #1404.

@review-notebook-app

Copy link
Copy Markdown

Check out this pull request on  ReviewNB

See visual diffs & provide feedback on Jupyter Notebooks.


Powered by ReviewNB

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, 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 introduces a comprehensive example for performing security alert investigations using the Gemini API's Antigravity managed agent and VirusTotal MCP. The provided notebook showcases best practices for interacting with remote tools, managing background interactions, and validating model-generated claims against raw tool output. It emphasizes secure handling of credentials and lifecycle management for sandbox environments.

Highlights

  • New Investigation Example: Added a new Jupyter notebook demonstrating alert investigation using the Antigravity managed agent, the Interactions API, and the VirusTotal MCP server.
  • Robustness and Safety: Implemented safeguards including single-request creation logic, local checkpointing for interaction recovery, and automatic sandbox cleanup.
  • Documentation Update: Registered the new notebook in the examples index within the examples README.
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 the 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 counterproductive. 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.

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. ↩

@github-actions github-actions Bot added status:awaiting review PR awaiting review from a maintainer component:examples Issues/PR referencing examples folder labels Oct 14, 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 adds a new Jupyter notebook, Alert_investigation_with_VirusTotal_MCP.ipynb, demonstrating how to use the Gemini API's Antigravity managed agent to investigate security alerts via a remote VirusTotal MCP server, and registers it in the examples README. Feedback recommends installing the SDK using the -U flag and >= operator to align with the repository style guide, and refactoring the custom SingleCreateClient to prevent bypassing the SDK's built-in error handling and prematurely blocking retries on transient failures.

},
"outputs": [],
"source": [
"%pip install -q \"google-genai==2.30.1\""

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.

medium

According to the repository style guide (line 25), the correct way to install the SDK is using >= with -U to specify the minimum required version rather than pinning a specific version with ==. This ensures users receive subsequent bug fixes and updates of the SDK while maintaining compatibility.

%pip install -U -q "google-genai>=2.30.1"
References
  1. The correct and most recent SDK is the Python genai one. '%pip install -U -q 'google-genai>=2.9.0'' is the right way to install the SDK. The version indicated should reflect the minimum version needed to use the features used in the notebook. (link)

Comment on lines +141 to +161
"class RequestFailed(RuntimeError):\n",
"\n",
" def __init__(self, status_code):\n",
" self.status_code = status_code\n",
" super().__init__(f\"HTTP {status_code}; request not retried.\")\n",
"\n",
"\n",
"class SingleCreateClient(httpx.Client):\n",
" create_sent = False\n",
"\n",
" def send(self, request, **kwargs):\n",
" if request.method == \"POST\" and request.url.path.endswith(\"/interactions\"):\n",
" if self.create_sent:\n",
" raise RuntimeError(\"Create already attempted; recover by interaction ID.\")\n",
" self.create_sent = True\n",
" response = super().send(request, **kwargs)\n",
" if response.is_error:\n",
" status_code = response.status_code\n",
" response.close()\n",
" raise RequestFailed(status_code)\n",
" return response\n",

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.

medium

By raising RequestFailed and closing the response on any HTTP error, the custom client bypasses the google-genai SDK's built-in error handling and parsing. This hides the detailed error payload returned by the Gemini API (such as invalid API key, quota exceeded, or bad request details), making debugging extremely difficult.

Additionally, setting create_sent = True before the request is sent means that if the request fails (e.g., due to a transient network issue or configuration error), the user is permanently blocked from retrying without restarting the kernel or re-running the client definition cell.

We can simplify the client to only mark create_sent = True upon a successful POST response, and let the SDK handle error responses normally so that detailed API error messages are preserved:

class SingleCreateClient(httpx.Client):
    create_sent = False

    def send(self, request, **kwargs):
        if request.method == "POST" and request.url.path.endswith("/interactions"):
            if self.create_sent:
                raise RuntimeError("Create already attempted; recover by interaction ID.")
        response = super().send(request, **kwargs)
        if request.method == "POST" and request.url.path.endswith("/interactions") and response.is_success:
            self.create_sent = True
        return response

Note that the RequestFailed class can be completely removed with this approach.

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

Labels

component:examples Issues/PR referencing examples folder status:awaiting review PR awaiting review from a maintainer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants