25 min read

Set Up mcp-virustotal HTTP with Localtonet

Install and verify the mcp-virustotal HTTP streaming server, then connect the local MCP endpoint through a Localtonet HTTP tunnel.

Remote MCP traffic reaches a local mcp-virustotal server through a Localtonet HTTP tunnel.
Localtonet forwards remote HTTP traffic to the locally running mcp-virustotal service.
MCP and AI Agents ยท mcp-virustotal ยท Localtonet ยท 2026

Run a VirusTotal MCP service locally, verify its streaming HTTP endpoint, and prepare it for controlled remote access

The mcp-virustotal project gives MCP-compatible AI clients access to VirusTotal reports, relationships, searches, behavior summaries, and collections. This guide starts with the service itself: prerequisites, source and Docker installation paths, HTTP streaming configuration, local verification, routine operation, and troubleshooting. After the local endpoint works, we show how to connect it through a Localtonet HTTP tunnel. Because the project's HTTP transport does not provide authentication, the remote-access section also explains the access-control boundary that must be addressed before exposing the endpoint.

๐Ÿ”’ Authentication required before untrusted exposure ๐ŸŒ HTTP streaming endpoint at /mcp โšก Local health check at /health

What mcp-virustotal does

mcp-virustotal is an independent Model Context Protocol server that connects AI agents to the VirusTotal v3 API. It is not affiliated with VirusTotal or Google, and it requires a VirusTotal API key supplied by the operator. An MCP client sends a structured tool request to the server, the server validates the arguments, makes the relevant VirusTotal API request, and returns a formatted result to the client.

The project supports two transports. The default is stdio, which is suitable when a desktop or command-line MCP client launches the server as a local child process. The second is httpStream, which runs mcp-virustotal as a standalone HTTP streaming service. This article focuses on the second mode because an HTTP service can be reached by compatible clients without each client launching its own local process.

The documented default HTTP port is 3000. The MCP endpoint path is /mcp, and the health-check path is /health. With the defaults, a local installation therefore exposes the MCP endpoint at http://localhost:3000/mcp and its health check at http://localhost:3000/health.

๐Ÿ”Ž Report tools Retrieve file, URL, IP address, and domain reports together with useful relationships for investigation.
๐Ÿงญ Relationship pivots Page through relationships for files, URLs, IP addresses, and domains instead of stopping at a single summary.
๐Ÿงช Search and behavior Search the VirusTotal corpus, request merged sandbox behavior summaries, and retrieve supported collections.
๐Ÿ”Œ Two transports Use the default stdio transport for locally launched clients or HTTP streaming for a separately running shared service.

Available tool groups

Tool group Documented tools Purpose
Reports get_file_report, get_url_report, get_ip_report, get_domain_report Retrieve primary reports and relevant relationships for common indicator types.
Relationship paging get_file_relationship, get_url_relationship, get_ip_relationship, get_domain_relationship Continue through supported relationships using cursor pagination.
Search and pivot search_vt, get_file_behaviour_summary, get_collection Search the corpus, inspect sandbox behavior, and retrieve collection information.

One operational detail is especially important for URL investigations. The documented get_url_report behavior checks for a cached VirusTotal report first. If there is no cached result, it submits the URL for analysis. Operators should account for that behavior when handling confidential, internal, pre-release, or otherwise sensitive URLs.

HTTP streaming is not the default

Starting mcp-virustotal without changing its transport uses stdio. To run the HTTP service described in this guide, set MCP_TRANSPORT=httpStream. Merely installing the npm package does not automatically create a listening HTTP endpoint.

Prerequisites and planning

Complete the service installation and local verification before creating a public tunnel. This order keeps application problems separate from connectivity problems. If /health is not reachable locally, a tunnel cannot correct the underlying process, configuration, build, or API-key issue.

Required software and credentials

  • Node.js 20 or newer for the source installation path.
  • A VirusTotal API key obtained from your own VirusTotal account.
  • Git and npm if you plan to clone and build the source repository.
  • Docker if you prefer the documented container workflow.
  • A Localtonet account and client for the later remote-access stage.
  • An MCP client that supports an HTTP streaming MCP endpoint if you want to consume the remotely reachable service.

The available evidence establishes Node.js 20 or newer as the project requirement. It also documents testing in continuous integration on Node.js 20, 22, and 24. It does not establish a complete operating-system support matrix, so this guide does not claim support for every desktop, server, container host, or processor architecture.

Choose the appropriate deployment path

Path Best suited to Important characteristic
Source build Development, testing, inspection, and operators who want the repository checkout Uses npm ci followed by the project's build and unit-test command.
Docker image Operators who prefer an isolated container and explicit host port mapping The documented run command publishes container port 3000 only on host loopback.
npx with stdio Claude Code, Codex CLI, Gemini CLI, and other clients that launch a local MCP process This is the project's quickstart path, but it does not by itself set up the standalone HTTP service covered here.

Decide where authentication will happen

The mcp-virustotal HTTP transport has no built-in authentication. Its project documentation recommends keeping the port on localhost or placing it behind an authenticating reverse proxy. Localhost binding protects the service only while access remains local. Once a tunnel intentionally makes that service reachable from the internet, localhost is no longer an access-control mechanism for requests arriving through the tunnel.

Plan an authentication boundary before remote exposure. A typical architecture places an authenticating HTTP component in front of mcp-virustotal and points the tunnel at that protected component rather than directly at port 3000. The exact reverse proxy, identity provider, certificate arrangement, and MCP client authentication support are deployment-specific and are not established by the supplied project evidence, so this guide does not invent a universal configuration.

Do not publish an unprotected endpoint for general internet access

Anyone who can invoke an unauthenticated MCP endpoint may be able to consume your VirusTotal API quota and submit indicators through your account. Establish authentication and appropriate authorization before sharing the public address with untrusted users or clients.

Install mcp-virustotal

The project documents both a source workflow and a Docker workflow for HTTP streaming. Select one. You do not need to run both installations on the same port.

Option 1: clone, install, build, and test from source

Clone the project repository, enter its directory, install the locked dependencies with npm ci, and run the test command:

git clone https://github.com/w0h1v/mcp-virustotal
cd mcp-virustotal
npm ci
npm test

The project states that npm test performs the build and unit tests without requiring a VirusTotal API key or network access. That makes it the appropriate first validation step. A successful run checks the build and local test suite before you introduce credentials or live API requests.

Do not proceed to HTTP startup if dependency installation, compilation, or tests fail. Capture the actual error, verify that your Node.js version is at least 20, and resolve the local build problem first. The runtime command used later expects the compiled build/index.js file to exist.

Option 2: build the Docker image

From the cloned repository directory containing the supplied Dockerfile, build the image with the documented tag:

docker build -t mcp-virustotal .

Building the image does not start the MCP service. It prepares the local image so that the container can be launched with the required environment variables and host port mapping in the configuration section.

About the npx quickstart

The published npm package can be launched with npx for stdio-based integrations. The project documents commands for Claude Code, Codex CLI, and Gemini CLI. Those commands are useful when the AI client and MCP process run together locally, but stdio does not create the standalone HTTP endpoint required by this article's remote-access workflow.

Avoid combining the two designs accidentally. If your only goal is a local desktop integration, stdio may be simpler and avoids opening a network listener. If your goal is a shared service reached through an HTTP-compatible MCP client, continue with httpStream.

Configure and start HTTP streaming

Configuration and terminal views for starting mcp-virustotal in HTTP streaming mode.
The server requires a protected API key, HTTP streaming settings, and a local listening endpoint.

mcp-virustotal reads its runtime configuration from environment variables. The API key is required. HTTP-specific variables select the transport, bind address, port, and endpoint path.

Variable Documented default Meaning
VIRUSTOTAL_API_KEY Required, no default Your VirusTotal API key.
MCP_TRANSPORT stdio Set to httpStream to run the standalone HTTP service.
MCP_HOST localhost Bind address used in HTTP streaming mode. The Docker image sets this to 0.0.0.0 inside the container.
MCP_PORT 3000 Listening port used by the HTTP service.
MCP_ENDPOINT /mcp Path used for MCP HTTP streaming requests.

Start the source build

After npm test has successfully produced and validated the build, start the HTTP streaming process with the documented variables:

MCP_TRANSPORT=httpStream MCP_PORT=3000 VIRUSTOTAL_API_KEY=your-key node build/index.js

Replace your-key with your real VirusTotal API key at runtime. The syntax above is the project's documented shell form. Environment-variable syntax differs between shells and operating systems, so use the equivalent supported by your environment if this inline form is not accepted.

With the defaults, the source process binds to localhost. That is the preferred starting point for local testing and for a Localtonet client running on the same host. Do not change the bind address merely because you intend to use a tunnel. Our client can target a loopback service when it runs on that same machine.

Start the Docker container

The documented Docker command publishes the container's port 3000 only on the host's loopback address:

docker run -p 127.0.0.1:3000:3000 -e VIRUSTOTAL_API_KEY=your-key -e MCP_TRANSPORT=httpStream mcp-virustotal

This mapping means the application listens inside the container while the Docker host exposes it as 127.0.0.1:3000. A Localtonet client running directly on that Docker host can target the mapped loopback port. If the Localtonet client runs on a different device, 127.0.0.1 on that device refers to the device itself, not the Docker host. In that topology, the client must be able to reach the service through a deliberately configured network path.

Protect the VirusTotal API key

Do not paste the key into articles, screenshots, support messages, public repositories, MCP client configurations that will be shared, or tunnel URLs. The key is read from the environment and sent by mcp-virustotal to VirusTotal. Use your environment's secret-handling facilities where practical.

Verify the service locally

A local HTTP request verifies that the mcp-virustotal streaming service is responding.
Local verification confirms the MCP service works before the tunnel is introduced.

Verification should proceed from the process outward. First confirm that the application remains running. Then test the documented health route. Finally connect an MCP client that supports the HTTP streaming transport and invoke a low-risk operation appropriate to your account and quota.

1

Confirm the process stays active

Keep the source process or Docker container running and inspect its immediate output for startup failures. If it exits, resolve that error before testing a URL.

2

Request the local health endpoint

Open http://localhost:3000/health or request it with an HTTP client. The project documents the route but does not establish a response body in the supplied evidence, so verify successful reachability rather than depending on an invented JSON schema.

3

Identify the MCP endpoint

With the defaults, the client endpoint is http://localhost:3000/mcp. A simple browser visit is not a substitute for an MCP protocol session, so use a client that supports the project's HTTP streaming transport.

4

Run a controlled MCP request

Configure the compatible client with the local endpoint and invoke an appropriate report operation. Start with a known, non-sensitive indicator and account for your VirusTotal quota before trying relationship paging or multiple tools.

A command-line health request can be made as follows:

curl http://localhost:3000/health

A reachable health route proves that an HTTP server is answering at that address. It does not prove that the VirusTotal API key is valid, that your account has quota, or that a particular MCP client is correctly negotiating the transport. Those concerns require an actual MCP tool call.

Interpret failures at the correct layer

  • If nothing answers on port 3000, inspect startup, binding, port conflicts, and container state.
  • If /health works but the MCP client cannot connect, check the endpoint path and the client's HTTP streaming compatibility.
  • If the client connects but a VirusTotal operation fails, inspect the API key, quota, request arguments, and application logs.
  • If local access works but remote access fails later, focus on the Localtonet client, selected device, tunnel state, local target, and public address.

Connect the working MCP service through Localtonet

Topology of a remote MCP client reaching mcp-virustotal through a Localtonet HTTP tunnel.
The tunnel carries public HTTP requests to the verified local MCP endpoint without exposing the API key.

Once http://localhost:3000/health works on the service host, an HTTP tunnel can connect that local listener to a public HTTPS address. Our client establishes an outbound connection to a Localtonet relay server, so this workflow does not require inbound router port forwarding, a public IP address, VPN setup, or inbound firewall changes.

The Localtonet client should run on the machine that can reach mcp-virustotal. For the source and Docker commands shown above, the simplest arrangement is to run our client on the same host and use the local target 127.0.0.1 with port 3000. If the service and client are on different devices, enter an address that is actually reachable from the Localtonet client instead of copying the loopback address.

1

Install and run the Localtonet client

Install our client for the operating system on the device that can reach the mcp-virustotal listener, then keep the client running. Use the current installation information provided by our platform because exact client commands can vary by operating system and version.

2

Authenticate or select the client device

Use the device-specific authentication token associated with that client, or select the connected device in the dashboard. Treat the token as a credential. Do not publish it, put it in sample code, or substitute a guessed value.

3

Select an available relay server

Choose a currently available server or region in the dashboard. Do not copy a hardcoded server code from an old tutorial because availability can vary by plan, region, and current product configuration.

4

Create the HTTP tunnel configuration

Select an HTTP tunnel and set its local target to the address and port reachable from the client device. For a same-host default installation, use 127.0.0.1 and 3000. Select the appropriate process type, such as Random Sub Domain, Custom Sub Domain, or Custom Domain, based on the options currently available to your account.

5

Start the tunnel

Creating the configuration does not make it active. Press the documented Start control and confirm that the selected client remains connected and the tunnel is running.

6

Use the assigned public address

Copy the public HTTPS base URL assigned to the running tunnel. Append /health for the health route and /mcp for the MCP endpoint unless you intentionally changed MCP_ENDPOINT. Stop or delete the tunnel when remote access is no longer required.

For example, if the dashboard displays a public base address represented here as https://your-assigned-host, the corresponding routes are:

https://your-assigned-host/health
https://your-assigned-host/mcp

These are placeholders, not real assigned endpoints. Always use the exact public URL shown for your running tunnel. Do not place a Localtonet auth token or VirusTotal API key in either URL.

HTTP and File Server tunnels can use a generated subdomain, a selected subdomain where supported, or a custom domain. Exact custom-domain DNS requirements must be checked against the current dashboard and documentation before changing DNS records. This guide does not provide guessed DNS targets or record values.

A tunnel has its own lifecycle

Saving or creating a Localtonet tunnel does not mean that it is running. The selected device must remain connected, the tunnel must be started, and the local mcp-virustotal process must continue listening. The public endpoint stops working if any part of that chain stops.

Verify the public path in stages

Start by requesting the public /health address. If it answers while the local health route also works, the HTTP path from the public address to the local service is established. Then configure the remote MCP client with the public /mcp address according to that client's own HTTP streaming configuration format.

MCP client configuration formats are not interchangeable. Some clients focus on locally launched stdio servers, while others support remote HTTP endpoints. The supplied evidence does not establish one universal JSON configuration for every client, so this guide intentionally avoids presenting an unverified configuration block.

Secure the remote MCP endpoint

Tunneling changes reachability, not the authentication behavior of the application behind it. The mcp-virustotal project explicitly states that its HTTP transport has no authentication. Do not assume that an assigned HTTPS URL automatically authenticates or authorizes MCP users.

๐Ÿ” Add an authentication boundary Place an authenticating HTTP layer in front of mcp-virustotal and point the tunnel at that protected listener rather than exposing the unauthenticated port directly.
๐Ÿ—๏ธ Keep credentials out of URLs Store the VirusTotal API key as a runtime secret and never append it to a public MCP or health-check address.
๐Ÿ“‰ Limit unnecessary exposure Run the tunnel only when remote access is required, and stop or delete it when the workflow is complete.
๐Ÿงพ Understand data submission Lookups send indicators to VirusTotal, and a URL report cache miss can submit that URL for analysis.

Recommended service layout

For an internet-reachable deployment, use a layered design:

  • The mcp-virustotal process listens on a local or otherwise restricted interface.
  • An authentication-capable HTTP component accepts requests from approved MCP clients.
  • That component forwards authorized MCP traffic to the local mcp-virustotal endpoint.
  • The Localtonet HTTP tunnel targets the protected HTTP component.
  • The MCP client connects to the assigned public HTTPS address using credentials supported by the chosen authentication layer.

Authentication products differ in how they handle streaming requests, headers, sessions, and long-lived HTTP connections. Test the full MCP exchange, not only a browser login page or health request. The reverse proxy must preserve the behavior required by the MCP HTTP streaming transport.

Consider quota and indicator sensitivity

The project notes that VirusTotal's public tier allows four requests per minute. Account limits may differ, and service-side limits can change, so treat the current VirusTotal account information as authoritative. Relationship paging and multi-step analyst workflows can generate several API operations even when a user asks one natural-language question.

The API key belongs to the operator, not the remote MCP user. That makes endpoint authorization important even if the data being requested appears public. An unauthorized user could consume quota, interfere with legitimate work, or cause indicators to be sent to VirusTotal.

Review indicators before submitting them. Hashes, domains, IP addresses, and URLs can reveal investigative interests or internal infrastructure. A cache miss for a URL report can cause the URL to be submitted for analysis. Do not use confidential internal URLs as casual connectivity tests.

Routine operation and maintenance

Starting the complete stack

A predictable startup order makes failures easier to diagnose:

  1. Start mcp-virustotal in HTTP streaming mode.
  2. Confirm the local /health route.
  3. Start any required authenticating HTTP layer and verify that protected local route.
  4. Run the Localtonet client on the device that can reach the selected local target.
  5. Start the saved HTTP tunnel.
  6. Verify the public health route, then connect the remote MCP client.

A process supervisor or container restart policy may be appropriate for a long-running deployment, but the project evidence supplied here does not prescribe one. Choose operational tooling suited to your environment and confirm that it passes the required environment variables without disclosing the API key.

Stopping access safely

Stop the Localtonet tunnel when public reachability is no longer needed. If the service itself is also unnecessary, stop the Node.js process or Docker container. Stopping only mcp-virustotal leaves the public route unable to reach its target, while stopping only the tunnel leaves the local service available on its configured local interface.

Delete a tunnel only when you no longer need its saved configuration. Stop is the appropriate lifecycle action for temporary suspension. Remember that a public address is available only while the selected client is connected and the tunnel is running.

Changing ports or endpoint paths

If you change MCP_PORT, update every dependent layer: the application's listening port, Docker publication if used, any authenticating reverse proxy target, and the Localtonet local target. If you change MCP_ENDPOINT, update the MCP client's endpoint URL. The documented health route remains /health; no evidence supplied here establishes a variable for changing that path.

Logs and testing

The documented log location is logs/mcp-virustotal-server.log in the package directory. In a containerized environment, first determine whether that path is retained after the container is removed. Persistence behavior depends on how the container and storage are configured.

Developers can run the documented smoke test against the real API:

VIRUSTOTAL_API_KEY=your-key npm run smoke

This test invokes all 11 tools and uses real API access. The project paces calls at 20 seconds for the public-tier rate limit and warns that the smoke test is not suitable for free tiers reduced to only a few lookups per day. It is not required merely to prove that the HTTP server is listening.

Troubleshooting mcp-virustotal and the tunnel

The process starts in stdio mode instead of HTTP mode

Confirm that MCP_TRANSPORT is exactly httpStream. The default is stdio. If the variable is missing, misspelled, or unavailable to the process, no standalone HTTP listener should be expected.

Nothing responds on localhost port 3000

Verify that the process remains running and that the configured port matches the address being tested. For a source build, confirm that build/index.js exists after the build and tests. For Docker, check that the container is running and that the port publication is 127.0.0.1:3000:3000 when using the documented command.

If another program already uses port 3000, select an available port with MCP_PORT and update the surrounding configuration consistently. This guide cannot identify an unused port on your machine, so verify the choice locally rather than copying an arbitrary alternative.

The health route works, but the MCP client does not

Confirm that the client supports the HTTP streaming transport and is configured with the full /mcp path. A health response proves basic HTTP reachability, not MCP protocol compatibility. If an authentication proxy is present, verify that it supports the streaming behavior and forwards required requests without transforming them incorrectly.

The API key is rejected

The project notes that a VirusTotal API key is usually 64 characters and should have no spaces or surrounding quotes. Recheck the value and restart the MCP client or server after changing configuration. Do not post the key while requesting assistance.

VirusTotal returns HTTP 429

A 429 response indicates rate limiting. The project documents four requests per minute for the public tier. Reduce request frequency, avoid unnecessary repeated pivots, and wait for the applicable quota window. Your actual account limits should be confirmed with VirusTotal.

Local access works, but the public health route fails

Check the chain in order:

  • The mcp-virustotal process is still running.
  • The local health address works from the Localtonet client device.
  • The correct Localtonet device is connected.
  • The saved HTTP tunnel targets the correct local IP address and port.
  • The tunnel has been started rather than only created.
  • You are testing the current public address assigned to that tunnel.

When Docker and our client run on the same host, target the published host address and port, not an unverified container-internal address. When they run on different hosts, test the chosen local target from the Localtonet client machine itself.

The public health route works, but tool calls fail

The tunnel is probably carrying HTTP traffic correctly if the public health route reaches the service. Move the investigation to the MCP endpoint path, client transport support, authentication layer, VirusTotal key, rate limit, tool arguments, and application log. Tool arguments are validated with zod schemas before requests are constructed, so invalid inputs can be rejected before any VirusTotal API call.

The endpoint unexpectedly became unavailable

Check every lifecycle dependency. The Localtonet client must be connected, the tunnel must be running, the local application must still be listening, and any proxy in between must be healthy. A restarted host or container may bring back one layer without restarting the others.

Frequently asked questions

Does mcp-virustotal require Node.js?

The documented source workflow requires Node.js 20 or newer. The Docker workflow packages the application in an image, although Docker itself must be available on the host.

What is the default mcp-virustotal HTTP endpoint?

In HTTP streaming mode, the documented default port is 3000 and the endpoint path is /mcp. On the local machine, that produces http://localhost:3000/mcp. The health check is available at http://localhost:3000/health.

Can I use the npx quickstart for this HTTP tunnel workflow?

The documented npx quickstart commands are designed around the default stdio transport. For a standalone HTTP service, run the built application or Docker image with MCP_TRANSPORT=httpStream.

Does the mcp-virustotal HTTP transport include authentication?

No. The project explicitly states that its HTTP transport has no authentication. Keep it local or place an authentication-capable HTTP layer in front of it before exposing it to untrusted networks or users.

Does a Localtonet HTTP tunnel automatically add MCP authentication?

Do not assume that tunneling adds application-level MCP authentication. The verified workflow here establishes public HTTP reachability to a local target. Protect the target with an appropriate authentication and authorization layer before sharing the public endpoint.

Must I open port 3000 on my router?

No. With Localtonet, our client establishes an outbound connection to a relay server. The local service can remain on a loopback address when our client runs on the same host, so inbound router port forwarding is not required.

Why does a URL lookup have additional privacy implications?

The project documents cache-first behavior for get_url_report. If VirusTotal has no cached report, the server submits the URL for analysis. Avoid using confidential or internal URLs unless that submission is acceptable.

Why does the tunnel stop working when the Localtonet client closes?

The tunnel is available only while the selected device is connected and the tunnel is running. The mcp-virustotal service and any authentication proxy must also remain active. Closing any required component interrupts the end-to-end path.

Connect your protected MCP endpoint with Localtonet

Build and verify mcp-virustotal locally, place authentication in front of its HTTP transport, then use our HTTP tunneling workflow to reach that protected service without inbound router port forwarding.

Get Started Free โ†’

Localtonet is a secure multi-protocol tunneling and proxy platform designed to expose localhost, devices, private services, and AI agents to the public internet supporting HTTP/HTTPS tunnels, TCP/UDP forwarding, mobile proxy infrastructure, file server publishing, latency-optimized game connectivity, and developer-ready AI agent endpoint exposure from a single unified control plane.

support