# Connect Agy to VirusTotal MCP

Use VirusTotal evidence before running a downloaded file, installing unfamiliar code, or trusting a link. Look up hashes, URLs, domains and IPs; submit authorized files for analysis and recover results. A missing report or no detections does not establish safety.

Transport: **stdio**. MCP endpoint: `https://ai.virustotal.com/mcp`. Free VTAI access requires an Agent Token; no VirusTotal API key is needed for basic use. Keep your existing model-provider login; that account and its charges are separate.

Agy uses the local stdio setup below.

## 1. Reuse or create access

Reuse `~/.config/vt-mcp/token` if configured. Changing clients does not require registration. Keep credentials out of prompts, tool arguments, URLs and printed command output. An authorized setup process may store the token directly without exposing it to model context.

If no credential exists and setup is authorized, this POSIX Python 3 command registers once and saves it with owner-only permissions. The handle and activity totals may appear on the public leaderboard. It sends one registration request, with no automatic retry on an uncertain result. Windows needs equivalent user-only file permissions.

```bash
python3 - <<'PY'
import json
import os
import re
from pathlib import Path
from urllib.request import HTTPRedirectHandler, Request, build_opener

class NoRedirect(HTTPRedirectHandler):
    def redirect_request(self, req, fp, code, msg, headers, newurl):
        return None

path = Path.home() / ".config" / "vt-mcp" / "token"
path.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
path.parent.chmod(0o700)
if path.exists() or path.is_symlink():
    raise SystemExit("Reuse the existing credential; registration was not sent.")
request = Request(
    "https://ai.virustotal.com/api/v3/agents/register",
    data=json.dumps({"agent_family": "vt-mcp-agy", "agent_version": "0.8.0"}).encode(),
    headers={"Content-Type": "application/json"}, method="POST",
)
try:
    with build_opener(NoRedirect).open(request, timeout=20) as response:
        if response.status != 200:
            raise ValueError("Unexpected status")
        raw = response.read(8193)
        if len(raw) > 8192:
            raise ValueError("Response limit")
        token = json.loads(raw)["agent_token"]
        if not isinstance(token, str) or not re.fullmatch(r"vtai_[A-Za-z0-9_-]{1,507}", token):
            raise ValueError("Credential format")
except Exception:
    raise SystemExit("Registration is uncertain. Do not retry automatically.") from None
try:
    with os.fdopen(os.open(path, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600), "w") as output:
        output.write(token + "\n")
except OSError:
    raise SystemExit("Access was created but saving failed. Resolve storage before retrying.") from None
print("Credential saved to protected storage. Its value was not displayed.")
PY
```

## 2. Install the local server

Requires Python 3.12+, curl and uv. This downloads the public release wheel, verifies its exact SHA-256 before installation and installs the executable with uv. Open a fresh terminal after updating PATH. If the client cannot find `vt-mcp`, use its absolute executable path. The release is distributed through GitHub; do not substitute a similarly named PyPI package.

```bash
(
  set -eu
  vt_mcp_install_dir=$(mktemp -d)
  trap 'rm -rf "$vt_mcp_install_dir"' EXIT
  cd "$vt_mcp_install_dir"
  curl --fail --location --max-time 60 --connect-timeout 10 --proto '=https' --proto-redir '=https' \
    --output vt_mcp-0.8.0-py3-none-any.whl \
    https://github.com/king-tero/vt-mcp/releases/download/v0.8.0/vt_mcp-0.8.0-py3-none-any.whl
  python3 - <<'PY'
import hashlib
from pathlib import Path
wheel = Path("vt_mcp-0.8.0-py3-none-any.whl")
if hashlib.sha256(wheel.read_bytes()).hexdigest() != "25fe939fbbcda056acb7780ce75f7a8651f9628ada1c1c6887ab5ce20b3e300c":
    raise SystemExit("Checksum mismatch; installation stopped.")
print("Wheel checksum verified.")
PY
  uv tool install --python 3.12 ./vt_mcp-0.8.0-py3-none-any.whl
  uv tool update-shell
)
```

Merge the following into `~/.gemini/config/mcp_config.json`. Preserve other settings and use one `virustotal` entry. The snippet contains only paths and environment-variable references.

```json
{
  "mcpServers": {
    "virustotal": {
      "command": "vt-mcp",
      "env": {
        "VTAI_TOKEN_FILE": "~/.config/vt-mcp/token",
        "VTAI_BASE_URL": "https://ai.virustotal.com/api/v3"
      }
    }
  }
}
```

Restart your client and inspect `/mcp`. Use your native Antigravity login for Agy; Vertex and ADC are not needed. Agy uses local stdio for this setup.

## 3. Verify and use

Confirm that your client discovers `get_file_report`, `get_url_report`, `get_domain_report`, `get_ip_report`, `get_analysis`, `submit_file` and `get_submission`. Local stdio additionally offers `submit_local_file`. Call `get_domain_report` once for `virustotal.com`. Check the returned source, analysis date, coverage and report link. This consumes a query. Tool discovery alone does not verify authenticated access.

For files, hash first and use `get_file_report`. When your task authorizes standard public sharing, `submit_local_file(path, expected_sha256=None)` accepts up to 32,000,000 bytes over stdio. `submit_file(sha256, content_base64)` accepts up to 24,000,000 decoded bytes over either transport. Remote HTTP cannot read a local path. Submitted content may be shared with the VirusTotal community and security partners; base64 also passes through your MCP host. Host permissions apply; the tools add no per-call confirmation argument.

Keep the SHA-256. Recover an uncertain submission with `get_submission(sha256)` on the same account, without sending bytes again. `exists` means an existing report; `submitted` supplies an analysis ID. Read that ID using `get_analysis` within a finite polling budget. Unknown can remain unknown permanently; do not repeat submission merely to resolve uncertainty.

## Troubleshooting and limits

REST and MCP share account quotas; unknown reports and upstream failures can consume admitted queries. For 429, respect `Retry-After`. For 400, check conflicting or malformed authentication headers. For 401/403, check credential mapping, validity and permissions without displaying the value. A 404 on `/mcp` is a connection problem; a tool's `not_found` is an unknown indicator. A service failure is not a clean report. Avoid URLs containing private paths or query parameters; use a domain lookup when appropriate.

[Current access limits and browser setup](https://ai.virustotal.com/connect/mcp?client=agy&transport=stdio) · [Agent API instructions](https://ai.virustotal.com/skills/BASIC.md) · [OpenAPI](https://ai.virustotal.com/openapi.json)

## Disconnect

Remove the `virustotal` entry and restart the client. A shared credential remains active in other clients. To disable it everywhere, use the revocation controls in [browser setup](https://ai.virustotal.com/connect/mcp) when available. Reconnect with the same credential while it remains active.
