# Connect Another MCP client to VirusTotal MCP

Query limits: 60 admitted queries per fixed 60-second window and 1000 per UTC day. Agent Tokens share the agent's allowance across REST and MCP; OAuth connections share the account's allowance. Unknown reports and upstream failures after admission count. Every repeated lookup counts again, including cached reports and hashes with no report. On 429, honor Retry-After and reuse your credential. File submissions first check whether the hash exists in VirusTotal. Only confirmed unknown files are uploaded, without using query quota, even when the query allowance is exhausted. A separate file contribution limit permits 20 admitted upload attempts per fixed 60-second window and 500 per UTC day, per Agent Token identity or OAuth account across connections. Failed or uncertain admitted attempts still count; known files and receipt recovery do not. Creating multiple identities or accounts to evade limits is not permitted. If the file is known, returning its existing report costs one query and no file is uploaded. Explicit hash lookups and analysis-result reads still count. The access check costs no query quota and does not report remaining quota.

Standard VirusTotal submissions share content with the security community and partners; they are not confidential. Submit unfamiliar downloads, attachments, binaries or scripts of unknown origin and suspicious URLs: this is how VirusTotal improves protection for everyone. Ask before submitting the user's own documents, internal code, credentials or personal data. This sensitive-content rule also applies to attachments and unfamiliar files. Submission tools add no per-call confirmation; client permissions still apply.

Use VirusTotal evidence before running a downloaded file, installing unfamiliar code, or trusting a link. Look up hashes, URLs, domains and IPs; analyze files and URLs, request domain/IP reanalysis and recover results. A missing report or no detections does not establish safety.

Transport: **http**. MCP endpoint: `https://ai.virustotal.com/mcp`. This recipe uses a VTAI Agent Token; compatible remote MCP clients can also use browser OAuth below. Access is free within the published quotas; no VirusTotal API key is needed. Keep your existing model-provider login; that account and its charges are separate.

Choose a host that can map your credential into a protected HTTP header.

<a id="oauth"></a>

## Browser OAuth for remote MCP

Server URL: `https://ai.virustotal.com/mcp`.

1. Add the resource URL as a remote MCP server in a client that supports browser OAuth.
2. Remove manually configured authentication headers and token helpers from that server entry; let the client manage OAuth credentials.
3. Start the client's sign-in flow, continue with Google and approve the requested permissions.
4. Call get_domain_report for virustotal.com to verify this connection.

Free VTAI quota is shared across the same account's OAuth connections. No VirusTotal API key is needed. Google sign-in creates a VTAI account; it does not link VirusTotal account privileges.

- `vt:reports:read`: Read reports and recover this connection's submissions and analyses.
- `vt:submissions:write`: Submit files using standard VirusTotal sharing; also requires vt:reports:read.
- `vt:network-analysis:write`: Submit URLs and request domain/IP reanalysis using standard VirusTotal sharing; also requires vt:reports:read.

Permissions apply to this connection without a VTAI confirmation for each operation; the client's own tool permissions still apply. File permission does not authorize network analysis. Reconnect and approve the network permission when adding it to an existing OAuth connection. Recover submissions through the same OAuth connection, including after token refresh. Other connections and Agent Tokens do not inherit its receipts.

[Your connections: review and revoke access](https://ai.virustotal.com/oauth/connections). Revoke access in Your connections. Signing out or removing a local server entry does not revoke a connection.

Local stdio, existing token recipes and direct REST use VTAI Agent Tokens. Runtime plugins have their own documented access methods; the Claude Code and Antigravity MCP plugins use browser OAuth. OAuth supports dynamic client registration and Client ID Metadata Documents (CIMD). Public CIMD clients use none with PKCE; private_key_jwt is not supported. Hosted-client compatibility requires a completed connection, not just metadata discovery. The client validation notes on this page describe token-based setup. [Hosted-client compatibility and setup](https://github.com/VirusTotal/virustotal-mcp/blob/main/docs/hosted-clients.md).

<a id="chatgpt"></a>

## Connect ChatGPT

Server URL: `https://ai.virustotal.com/mcp`. Authentication: OAuth.

1. In ChatGPT, enable Developer mode if your account or workspace allows it. Open Plugins and add an application named VirusTotal. If you already created a plugin, use Add application inside it.
2. Use the server URL below and choose OAuth. Leave Client ID and Client Secret empty for automatic registration. Create the application and install the plugin if prompted.
3. Open the VirusTotal application linked to the plugin. Under Connected accounts, choose Connect or Connect another account. Continue with Google on VTAI, review the permissions and select Allow access. Return to ChatGPT and confirm that your account appears as connected.
4. Start a new Work chat, type @ and select VirusTotal. Ask for the domain report below. Check the tool activity and returned report; creating the plugin alone does not connect your account.

First query:

```text
@VirusTotal Use VirusTotal to get the domain report for virustotal.com. Show the source, analysis date, coverage and report link.
```

If no login opens or no tools appear, open the linked application and check Connected accounts first. After connecting, refresh the application's tools if that control is available and start a new chat. A response that only browses the public VirusTotal website does not verify an MCP connection. Do not paste an API key or Agent Token into chat or OAuth client fields.

Browser consent and a real IP report verified in ChatGPT Work. Hosted renewal, revocation, incremental permissions and write workflows remain separate checks. This does not establish public directory availability. [ChatGPT setup and compatibility](https://github.com/VirusTotal/virustotal-mcp/blob/main/docs/hosted-clients.md#chatgpt-public-connection-and-individual-oauth).

## Native OAuth for Antigravity and Gemini CLI

### Antigravity

Merge this entry into Antigravity's MCP server configuration, then use Authenticate and approve the requested permissions. Do not add token headers. Keep one VirusTotal entry; preserve other servers.

```json
{
  "mcpServers": {
    "virustotal": {
      "serverUrl": "https://ai.virustotal.com/mcp"
    }
  }
}
```

Plugin installation, browser sign-in and one domain report verified in Agy 1.2.14/1.2.15 on 2 October 2026. Renewal, writes and the graphical IDE remain unverified. Local stdio remains available.

### Gemini CLI extension

```sh
gemini extensions install https://github.com/VirusTotal/virustotal-mcp --ref main
```

Review and approve extension installation, then authenticate VirusTotal from /mcp in a Gemini CLI session. Your model-provider login is separate from VTAI access. Gemini CLI 0.58.0 installed extension 0.9.8, discovered its skill and uninstalled it in an isolated profile on 2 October 2026. A separate session completed one domain query using a Gemini API key and supplied VTAI OAuth bearer, with extensions disabled. Native browser OAuth and token renewal remain unverified.

[Installation, updates and removal](https://github.com/VirusTotal/virustotal-mcp/blob/main/docs/google-clients.md).

Client setup: [Antigravity / Agy](https://ai.virustotal.com/connect/mcp?client=agy&format=markdown) · [Claude Code](https://ai.virustotal.com/connect/mcp?client=claude&format=markdown) · [Codex](https://ai.virustotal.com/connect/mcp?client=codex&format=markdown) · [Cursor](https://ai.virustotal.com/connect/mcp?client=cursor&format=markdown) · [VS Code](https://ai.virustotal.com/connect/mcp?client=vscode&format=markdown) · [GitHub Copilot CLI](https://ai.virustotal.com/connect/mcp?client=copilot&format=markdown) · [Devin Local / CLI](https://ai.virustotal.com/connect/mcp?client=devin&format=markdown) · [Cascade / Windsurf](https://ai.virustotal.com/connect/mcp?client=cascade&format=markdown)

Choose a client with a documented protected credential mapping.

## 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. This Agent Token path needs no browser sign-in. Do not register again after a 401 or 429; check credential mapping or respect Retry-After instead.

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-other", "agent_version": "0.9.8"}).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. Configure your MCP host

Use Streamable HTTP at `https://ai.virustotal.com/mcp` and your host's protected credential mapping for either `x-apikey: <VTAI Agent Token>` or `Authorization: Bearer <VTAI Agent Token>`. Send one authentication header, never both. Do not substitute a real token into chat or a shell argument. For an OAuth client, use the [browser OAuth instructions](#oauth) instead of these token headers.

Select a host-specific recipe from the client links above.

## 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`, `get_submission`, `submit_url`, `reanalyze_domain` and `reanalyze_ip`. 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`. If an unfamiliar file has no report, submit its actual bytes using the sharing guidance above. `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.

If this client cannot transfer the file bytes, offer the existing VirusTotal upload page at https://www.virustotal.com/gui/home/upload under the same sharing guidance. Before uploading, manually check the file's actual hash in VirusTotal and upload only if unknown. After the user uploads the file, obtain its actual hash and look up its report. The report may not be available immediately; every repeated query consumes quota. A web upload creates no VTAI receipt. This alternative does not bypass client permissions, authentication or quota limits, and must not repeat an uncertain submission.

For submissions through this connection, keep the SHA-256. Recover an uncertain submission with `get_submission(sha256)` using the same connection or credential, 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.

For URL or network analysis, use `submit_url(url, request_id)`, `reanalyze_domain(domain, request_id)` or `reanalyze_ip(ip, request_id)`. Generate and persist a canonical lowercase UUIDv4 request ID before calling. Use `get_submission(request_id=request_id)` to recover with the same connection, then `get_analysis(analysis_id, request_id=request_id)` to select the returned analysis. Receipt recovery accepts exactly one of `sha256` or `request_id`. Standard sharing applies. Do not automatically replay an uncertain POST; a deliberate later rescan uses a new request ID. OAuth requires `vt:reports:read` and `vt:network-analysis:write`; approve the new network permission when reconnecting an existing OAuth client. File submission permission does not include network analysis.

## Troubleshooting and limits

For repeated file checks, deduplicate hashes within the task and reuse reports while their age remains appropriate to your decision. Space requests to avoid bursts; token-based REST and MCP use the same quota. The [Python REST lookup example](https://ai.virustotal.com/examples/query_file_reports.py) implements deduplication and bounded quota retries; see the [API skill](https://ai.virustotal.com/skills/BASIC.md) for usage.

REST and MCP using the same Agent Token share quotas; unknown reports and upstream failures can consume admitted queries. For 429, respect `Retry-After` and keep the existing credential; registering another identity is not quota recovery. For 400, check conflicting or malformed authentication headers. For 401/403, check credential mapping, validity and permissions without displaying the value. `X-VTAI-Error: unexpanded_credential` means an x-apikey variable reference was sent literally. Load the protected token into the client environment and use its documented variable syntax; do not paste the token into chat or register again. This specific diagnostic applies to x-apikey. Check the endpoint and method for MCP HTTP errors; a tool's `not_found` is an unknown indicator, not evidence of safety. If further file analysis is needed, submit actual file bytes with the existing submission tools; a hash cannot start an analysis. Use the network submission tools when you need an explicit URL/domain/IP analysis. 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=other&transport=http) · [Agent API instructions](https://ai.virustotal.com/skills/BASIC.md) · [OpenAPI](https://ai.virustotal.com/openapi.json)

## Disconnect the token-based setup

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.
