VPNDetectionVPNDetection

MCP Server

The official Model Context Protocol server for the VPNDetection API.

See on GitHub

Getting Started

No API key needed to start. The free tier answers ip and is_vpn, and allows 1000 requests per day per source address.

Add this to your MCP client's config:

{
  "mcpServers": {
    "vpndetection": {
      "command": "npx",
      "args": ["-y", "vpndetection-mcp"]
    }
  }
}

Then ask it something like "is 45.83.91.1 a VPN?".

Requires Node.js 22 or newer.

With an API key

A key unlocks the provider name, the classification databases and the proxy families. Put it in the environment:

{
  "mcpServers": {
    "vpndetection": {
      "command": "npx",
      "args": ["-y", "vpndetection-mcp"],
      "env": { "VPNDETECTION_API_KEY": "your-key" }
    }
  }
}

VPNDETECTION_BASE_URL overrides the endpoint if you need to point somewhere else.

Tools

ToolWhat it answers
lookup_ipClassify one address.
lookup_ipsClassify up to 100 addresses in one call, keyed by address.
list_databasesThe databases your organization is licensed for.
database_metadataA database's columns, sample rows, row count, build date and file sizes.
database_checksumThe published digests for one database file.
list_downloadsYour organization's recent download attempts, refusals included.

Every tool is read-only. There is deliberately no download tool: the databases run to several GB, which is not something an agent should pull into a conversation. Fetch them with the client libraries or the API instead.

Reading a result

Each lookup comes back with a coverage block beside it:

{
  "result": { "ip": "45.83.91.1", "is_vpn": true },
  "coverage": {
    "included": ["ip", "is_vpn"],
    "not_included": ["is_hosting", "is_tor", "hosting", "tor", "..."],
    "note": "The fields in not_included were not returned, because this API key's plan does not include them. ..."
  }
}

This matters more here than in a normal client library. A field missing from a result means your plan doesn't include it, never "we checked and found nothing" - and a model reading the result on its own will otherwise treat the absence as a negative answer. coverage states the difference explicitly so it can't.

On this page