IPGeolocation MCP Server
This read-only MCP server provides IP intelligence, geolocation, security, ASN, abuse-contact, timezone, astronomy, currency, and user-agent tools through IPGeolocation.io APIs.
Look up location, timezone, currency, company/ASN, network, security/threat indicators, and abuse contacts for an IP or domain.
Run bulk IP geolocation and bulk security checks for up to 250 inputs per request.
Get the server machine's public IP without an API key.
Look up current timezone details or convert times between locations, airports, coordinates, or UN/LOCODEs.
Retrieve sunrise/sunset, moon phase, twilight, and related astronomy data for one date or a date range up to 90 days.
Parse one or up to 250 user-agent strings into browser, device, OS, engine, and bot/crawler details.
Read oversized cached results page-by-page with
get_cached_resultat zero credits.
Provides tools to look up timezone information, current local time, and specific airport details using 3-letter IATA airport codes.
IPGeolocation.io MCP Server
The official IPGeolocation.io MCP server provides 17 tools for accurate IP geolocation, company information, ASN and network data, IP security (VPN, proxy, Tor, bot, hosting and spam detection), abuse contacts, time zones, astronomy, currency data and user-agent parsing.
MCP (Model Context Protocol) connects your client to these tools. Your client or host must support launching a local command over stdio. See Install by Client for configuration examples.
This README describes 2.0.2. The npx commands and Cursor install link below follow npm's latest tag, including future major releases. Restart the server to load an update; npm reuses cached package files when the selected version is unchanged. See the changelog for release details.
Item | Value |
Package |
|
Version |
|
Release date | 2026-10-27 |
Transport |
|
Node.js |
|
Quick Start
Merge this entry into your client's private configuration, keeping any existing servers. See Install by Client for the configuration location. Cursor also has a one-click installer.
{
"mcpServers": {
"ipgeolocation": {
"command": "npx",
"args": ["-y", "ipgeolocation-io-mcp@latest"],
"env": {
"IPGEOLOCATION_API_KEY": "<YOUR_API_KEY>"
}
}
}
}Reload the server or restart your client.
Ask "Where is 8.8.8.8 located?"
Related MCP server: GeoIP MCP Server
Table of Contents
Install by Client
Requirements
Node.js 22 or later for npm/source installs, or a bundle host with a compatible Node.js runtime
npxavailable for the npm configuration examplesAn IPGeolocation.io API key for most API tools
Use a supported Node.js release with its latest security updates.
get_my_ip requires no API key. The other 15 API tools require one. get_cached_result reads results already held in memory; use the same API key as the original lookup.
Sign up for a free IPGeolocation API key
Use a private user configuration or your client's secret/environment settings for the real key. Keep keys out of committed project configuration. Each client below uses the Quick Start server entry unless its format differs.
Codex CLI
Set IPGEOLOCATION_API_KEY in your private shell environment before running these commands. The variable reference keeps the key value out of the command you type and its shell history.
codex mcp add ipgeolocation --env "IPGEOLOCATION_API_KEY=$IPGEOLOCATION_API_KEY" -- npx -y ipgeolocation-io-mcp@latest
codex mcp listStart a new Codex session after adding the server.
Claude Desktop
Install the published server from its Claude Marketplace listing. In Claude Desktop, open Settings > Extensions > Browse extensions, find IPGeolocation.io MCP Server, and configure your API key during installation. See Anthropic's desktop extension guide. The directory distributes the approved published bundle; its refresh can lag GitHub Releases. Check the installed version, or download the versioned bundle below.
For manual npm configuration, open Settings > Developer > Edit Config in Claude Desktop. This opens claude_desktop_config.json:
macOS:
~/Library/Application Support/Claude/claude_desktop_config.jsonWindows:
%APPDATA%\Claude\claude_desktop_config.json
Merge the Quick Start entry into mcpServers.
Fully quit and reopen Claude Desktop after saving. See the official local-server setup guide.
For clients that install MCP Bundles, download the published v2.0.2 .mcpb bundle from GitHub Releases. The bundle contains the server and its dependencies; its host still needs a Node.js 22+ runtime. Enter your API key when the host prompts for bundle configuration.
Cline
In Cline, open MCP Servers > Configure > Configure MCP Servers. Add the Quick Start entry under mcpServers in the settings JSON. Cline CLI uses ~/.cline/data/settings/cline_mcp_settings.json by default. See Cline's MCP guide.
Restart Cline after saving.
Cursor
One-click install:
Or add to .cursor/mcp.json for this project, or ~/.cursor/mcp.json for all projects. See Cursor's MCP guide.
{
"mcpServers": {
"ipgeolocation": {
"type": "stdio",
"command": "npx",
"args": ["-y", "ipgeolocation-io-mcp@latest"],
"env": {
"IPGEOLOCATION_API_KEY": "<YOUR_API_KEY>"
}
}
}
}Restart Cursor after saving.
Cursor plugin
This repository includes a Cursor plugin for ipgeolocation-io-mcp. The plugin runs locally over stdio and requires Node.js 22 or later.
To install it locally, clone this repository into a new directory under ~/.cursor/plugins/local/, reload Cursor, and open Customize > Plugins.
Local plugin: set
IPGEOLOCATION_API_KEYin the environment that launches Cursor. The plugin reads the key from that environment.Marketplace install: set the key in the plugin's private configuration.
With an empty or unset API key, get_my_ip still works. API tools that require a key return a missing-key error without sending a request.
To load a local checkout in Cursor CLI:
agent --plugin-dir /absolute/path/to/ipgeolocation-io-mcpAPI requests that need a key use your account's plan and credits. The get_cached_result tool reads saved response pages without making another API request.
Install this server by only one method, because using more than one creates duplicate tool entries. You can keep any other servers in your existing configuration.
Windsurf / Cascade
In Cascade's ... (Actions) menu, choose Open MCP config file in the MCPs section. Merge the Quick Start entry into the file opened by your installed version; configuration paths vary by release. See the vendor's Cascade MCP guide for the active agent and configuration location in newer releases.
Save the file and reload the server in the client.
Kiro Powers
The Kiro Power provides 17 tools for IP geolocation, company information, ASN and network data, IP security (VPN, proxy, Tor, bot, hosting and spam detection), abuse contacts, time zones, astronomy, currency data and user-agent parsing. It runs ipgeolocation-io-mcp locally over stdio, follows npm's latest tag and requires Node.js 22 or later. Import the packaging/kiro folder through Powers > Add Custom Power and follow the setup guide to configure your private API key. Most tools require a key; access and credits depend on your plan.
VS Code / GitHub Copilot
Run MCP: Add Server from the Command Palette, choose a local command, and use npx -y ipgeolocation-io-mcp@latest. Choose Copilot Global for private user settings or .mcp.json for a portable workspace configuration. Add IPGEOLOCATION_API_KEY to the server's environment.
The portable .mcp.json format uses the top-level mcpServers object shown in Quick Start.
Use the server's Start action and approve its configuration when prompted. Existing .vscode/mcp.json files use a top-level servers object instead. See VS Code's MCP setup guide.
Glama
You can try the server on Glama directly. Only IPGEOLOCATION_API_KEY is required. Leave other environment variable fields empty unless you want to change cache, timeout, or output limits.
If you don't have a key yet, create a free IPGeolocation API key.
Any Other MCP Client
Use the ipgeolocation server entry from Quick Start in your client's configuration format. The client must support launching a local stdio process. A client that accepts only a remote MCP URL needs a hosted endpoint; this package supplies the server command.
Verify It Works
Try these after setup:
Prompt | Expected tool |
Where is 8.8.8.8 located? |
|
For IP 49.12.212.42, give me threat indicators, company, ASN, and city. |
|
Show threat indicators and the abuse contact email for 2.56.12.11. |
|
For AS1, list upstream ASN numbers only. |
|
Convert 2026-03-07 09:30 from New York to Tokyo time. |
|
Give sunrise times for Karachi from 2026-03-10 to 2026-03-15. |
|
Parse this user agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 |
|
Tools by Plan
Version 2.0.2 exposes 16 API tools and get_cached_result, a zero-credit page reader. Bulk tools accept 250 inputs by default; the effective ceiling is the lower of the two item-limit settings.
Listed costs apply to successful upstream requests. Cache hits and cached-page reads use no additional credits. The API's X-Credits-Charged response header establishes actual billing; see the credit rules.
Free Plan
1,000 credits per day. These 7 API tools provide their documented core data; get_cached_result also reads previously returned pages for 0 credits:
Tool | Credits | What it does |
| 1 | Location, timezone, currency, ASN for one IP |
| 0 | Public IP of the machine running the server |
| 1 | Currency and country metadata for one IP |
| 1 | Timezone by name, location, IP, airport code, or UN/LOCODE |
| 1 | Convert time between two locations |
| 1 | Sunrise, sunset, moonrise, moonset, twilight, moon phase for one date |
| 1 | Daily astronomy data for a date range (up to 90 days) |
lookup_company also returns basic ASN ownership on free plans, without company details. lookup_network returns a local error if the API omits the paid network data. The API documentation describes bulk geolocation as paid-only; live checks with a free-plan key also returned basic bulk results. Plan access is determined upstream, so free bulk support should not be assumed from this observation.
Paid Plans
All 17 tools, including the zero-credit cached result reader. Paid plans also add network, company, and extended asn fields to lookup_ip, plus the include parameter for security, abuse, hostname, liveHostname, hostnameFallbackLive, user_agent, geo_accuracy, dma_code, or *.
Tool | Credits | What it does |
| 1 per IP | Batch geolocation, 250 inputs by default |
| 2 | VPN, proxy, Tor, bot, spam, and threat flags |
| 2 per IP | Batch threat checks |
| 1 | Company name and ASN holder for one IP |
| 1 | Route prefix, connection type, anycast status |
| 1 | Parse one UA string into browser, device, OS, engine |
| 1 per UA | Batch UA parsing, 250 strings by default |
| 1 | ASN details, peers, upstreams, downstreams, routes, WHOIS |
| 1 | Abuse contact emails, phone, address, route |
Credit math for lookup_ip with include:
Combination | Total credits |
Base lookup | 1 |
| 3 |
| 2 |
| 4 |
| 2 |
| 1 |
For current plan details and pricing, see the IPGeolocation.io pricing page.
Tool Reference
Tool arguments must match the advertised schema. Unknown parameters are rejected locally before any API request, so a misspelled selector cannot silently look up the server's IP.
Coordinates, including conversion selectors, and elevation take string values, such as "24.86" and "10". force_refresh takes a boolean.
lookup_ip
Single IP or domain lookup through the IP Geolocation API. Free and paid. 1 credit for base IP data.
Use this when you need location, timezone, currency, or ASN for one IP address. On paid plans you can add include modules to pull security, abuse, or hostname data in the same call, which avoids extra requests.
Free plan returns base location, country metadata, currency, timezone, and basic ASN. Paid plans add network, company, extended ASN, and the include parameter. Note that domain lookups require a paid plan.
Parameter | Required | Description |
| No | IPv4, IPv6, or domain. Domain lookup requires a paid plan. |
| No | Response language. Non-English requires a paid plan. |
| No | Extra modules: |
| No | Comma-separated fields to return |
| No | Comma-separated fields to exclude |
| No | Skip the cache and hit the API directly |
Tip: combining include with fields can cut your credit cost. For example, include=security&fields=security costs 2 credits instead of 3 because you skip the base geolocation response. Similarly, include=abuse&fields=abuse costs 1 credit instead of 2.
Fields enable the optional modules they need. These modules require a paid plan:
Selected field | Enabled module |
|
|
|
|
|
|
Accuracy and DMA values appear inside location. An explicit include keeps its module present even if fields omits it. You can exclude nested fields, but a root named by fields or an explicit include stays present. include=* follows field selection and exclusions without protecting those roots. Cached results follow the same rules as fresh responses.
bulk_lookup_ip
Batch IP lookup. Paid. 1 credit per IP.
Takes an array of IPs or domains (up to 250 by default). The batch limit is the lower of IPGEOLOCATION_MCP_MAX_BULK_ITEMS and IPGEOLOCATION_MCP_MAX_RESULT_ITEMS. Supports the same include, fields, and excludes options as lookup_ip.
Parameter | Required | Description |
| Yes | Array of IP addresses or domains |
| No | Response language |
| No | Extra modules per IP |
| No | Comma-separated fields to return per IP |
| No | Comma-separated fields to exclude per IP |
| No | Skip the cache |
get_my_ip
Returns the public IP of the machine running the server. Free. 0 credits. No API key needed.
Takes no parameters. Always hits the network (not cached). Useful as a quick check to confirm the server process is up.
check_security
Threat and anonymity data for one IP through the IP Security API. Paid. 2 credits.
Returns threat score, VPN/proxy/Tor flags, provider names, confidence scores, bot/spam indicators, anonymity flags, and cloud-provider status.
If the same prompt also asks for location or ASN, use lookup_ip with include=security to get them in one request. It costs 3 credits, the same as a separate security check and base lookup. Add abuse to include when abuse contacts are also needed.
Parameter | Required | Description |
| No | IP address to check |
| No | Comma-separated fields to return |
| No | Comma-separated fields to exclude |
| No | Skip the cache |
bulk_security_check
Batch version of check_security. Paid. 2 credits per IP. Accepts up to 250 inputs by default, subject to the same bulk limits as bulk_lookup_ip.
Parameter | Required | Description |
| Yes | Array of IP addresses |
| No | Comma-separated fields to return per IP |
| No | Comma-separated fields to exclude per IP |
| No | Skip the cache |
get_timezone
Current time and timezone details for a location through the Time Zone API. Free and paid. 1 credit.
Accepts IANA timezone names, coordinates, IP addresses, airport codes (IATA/ICAO), or UN/LOCODEs. The response includes timezone offsets, date/datetime variants, current_time, current_time_unix, time_24, time_12, week, month, year, timezone abbreviations, and DST transition details.
With no selector, the API uses the server machine's public egress IP, which can differ from your IP.
Always hits the network (not cached) because it returns the current time.
Parameter | Required | Description |
| No | IANA timezone name (e.g., |
| No | Latitude and longitude |
| No | City or address string |
| No | IP address |
| No | IATA airport code |
| No | ICAO airport code |
| No | UN/LOCODE |
| No | Response language. Non-English requires a paid plan. |
convert_timezone
Converts a time between two locations. Free and paid. 1 credit.
Provide one source selector and one destination selector using an IANA time zone, coordinates, a city/address, an airport code, or a UN/LOCODE. If you omit time, the API converts the current time. This tool does not accept IP selectors or lang and always calls the API (not cached).
Parameter | Required | Description |
| No |
|
| No | IANA timezone names |
| No | Source coordinates |
| No | Destination coordinates |
| No | City/address strings |
| No | IATA airport codes |
| No | ICAO airport codes |
| No | UN/LOCODEs |
get_astronomy
Sun and moon data for one location on one date through the Astronomy API. Free and paid. 1 credit.
Returns sunrise, sunset, moonrise, moonset, morning and evening twilight, solar noon, day length, moon phase, sun/moon status flags, and live sun/moon position (altitude, azimuth).
This tool always calls the API, including when date is set; it does not use the response cache.
Parameter | Required | Description |
| No | Coordinates (highest priority when given) |
| No | City or address |
| No | IP address |
| No |
|
| No | Meters, 0 to 10000 |
| No | IANA name to control output times |
| No | Response language. Non-English requires a paid plan. |
get_astronomy_time_series
Astronomy data for a date range, up to 90 days. Free and paid. 1 credit per request.
Each daily entry includes mid_night, night_end, morning, sunrise, sunset, evening, night_begin, sun_status, solar_noon, day_length, moon_phase, moonrise, moonset, and moon_status. Use this instead of calling get_astronomy repeatedly for a range.
Parameter | Required | Description |
| Yes | Start date ( |
| Yes | End date ( |
| No | Coordinates (highest priority when given) |
| No | City or address |
| No | IP address |
| No | Meters |
| No | IANA name to control output times |
| No | Response language. Non-English requires a paid plan. |
| No | Skip the cache |
parse_user_agent
Parses one UA string into browser, device, OS, and engine data through the User Agent API. Paid. 1 credit.
Also classifies bots and crawlers. Note: this parses the uaString you pass in. It does not infer a caller UA from the MCP connection itself.
Parameter | Required | Description |
| Yes | The user-agent string to parse |
| No | Skip the cache |
Returns name, type, version, device, engine, and operating_system.
bulk_parse_user_agent
Batch version of parse_user_agent. Paid. 1 credit per string.
Takes up to 250 strings per request by default. The batch limit is the lower of IPGEOLOCATION_MCP_MAX_BULK_ITEMS and IPGEOLOCATION_MCP_MAX_RESULT_ITEMS.
Parameter | Required | Description |
| Yes | Array of user-agent strings |
| No | Skip the cache |
lookup_company
Company details and ASN ownership for one IP. Company details require paid; free plans return basic ASN only. 1 credit.
Returns company and asn objects. lookup_ip returns the same data plus location, timezone, and more. Use this when the company/ASN pair is all you need and you want a smaller response.
Parameter | Required | Description |
| No | IP address |
| No | Skip the cache |
lookup_currency
Currency, country calling code, TLD, and languages for one IP. Free and paid. 1 credit.
Returns currency and country_metadata objects.
Parameter | Required | Description |
| No | IP address |
| No | Skip the cache |
lookup_network
Route prefix, connection type, and anycast status for one IP. Paid. 1 credit.
Returns a network object with connection_type, route, and is_anycast. If the API omits network data, the tool returns a local error instead of an empty success. This does not invent an upstream HTTP status, and the API call may already have consumed credits.
Parameter | Required | Description |
| No | IP address |
| No | Skip the cache |
lookup_asn
Network allocation and relationship data through the ASN API. Paid. 1 credit.
Use this tool for ASN details and optional peers, upstreams, downstreams, routes, and WHOIS datasets. Request the datasets you need with include, then filter the cached result to retrieve different slices. lookup_ip also provides ASN metadata as part of an IP lookup.
fields automatically enables optional datasets it references, such as upstreams.as_number. excludes alone does not request extra datasets.
Parameter | Required | Description |
| No | ASN (e.g., |
| No | IP address to resolve to an ASN |
| No |
|
| No | Comma-separated fields to return |
| No | Comma-separated fields to exclude |
| No | Skip the cache |
get_abuse_contact
Abuse contact details for one IP through the IP Abuse Contact API. Paid. 1 credit.
Returns the abuse route, country, contact name, organization, address, email addresses, and phone numbers. If you also need geolocation or security data for the same IP, use lookup_ip with include=abuse (or include=security,abuse) to get everything in one call.
Parameter | Required | Description |
| No | IP address |
| No | Comma-separated fields to return |
| No | Comma-separated fields to exclude |
| No | Skip the cache |
get_cached_result
Read a page from a previous oversized result. Free and paid. 0 credits. Added in 2.0.1.
Parameter | Required | Description |
| Yes | The previous response's |
Use the same server process and API key. Page reads extend the snapshot's idle expiry and never call the API, including on failure. See Cached Result Pagination for the response fields and a complete recovery example.
Prompt Examples
For a paid IP investigation, call lookup_ip once with ip: "49.12.212.42", include: "security,abuse", and fields: "location,company,asn,security,abuse". This combines location, ownership, threat indicators, and abuse contacts for an estimated 4 credits. Describe the evidence and any unknown fields; apply the user's policy before recommending an allow/block decision.
For a mixed batch, call bulk_lookup_ip with ips: ["8.8.8.8", "10.0.0.1", "1.1.1.1"] and fields: "location.country_name". Inspect structuredContent.errors to identify the private input and use the successful records directly. The two valid IP lookups cost an estimated 2 credits; the private IP is not billed. Split larger batches at the advertised input limit.
An ASN identifies a network that announces IP routes. Anycast lets one IP be served from multiple locations, so its location need not identify the server that handled a particular request. A bogon address is reserved or otherwise not publicly routable. Upstream in an error means the IPGeolocation.io API contacted by this server.
IP location is an estimate. Use include=geo_accuracy where available to assess uncertainty. Threat scores and VPN/proxy flags are signals for investigation, not guarantees of harmless or malicious traffic. Treat missing, null, or unknown indicators as unavailable, not as false. Combine location, ownership, security signals, and abuse contacts with your own allow/block policy.
Inspect IP threat indicators
Show the threat indicators and city for 49.12.212.42 so I can assess it against our network policy.
Check these IPs for VPN, proxy, Tor, bot, and spam indicators: 49.12.212.42, 2.56.12.11, 8.8.8.8
For 49.12.212.42, tell me the threat score, whether it is a cloud provider, and whether it looks like a relay.
Find who owns an IP
Who uses 1.1.1.1 and which ASN routes it?
For AS24940, list upstream ASN numbers only.
Is this IP anycast and what route prefix is announced for it: 1.1.1.1
Get abuse contacts
For IP 2.56.12.11, give me the abuse contact email, phone number, and organization.
I need the abuse contact for 1.0.0.0 and the network route involved.
For this IP, show me the abuse contact details only: 1.1.1.1
Timezone lookups and conversions
What time is it in Tokyo right now?
Convert 2026-03-07 09:30 from New York to Tokyo time.
What is the current local time at JFK airport?
Sunrise, sunset, and moon data
Give sunrise and sunset for London on 2026-06-21.
Show sunrise times in Karachi from 2026-03-10 to 2026-03-15.
For New York, give me moon phase and day length on 2026-07-17.
Parse user-agent strings
Parse this user agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/601.3.9 (KHTML, like Gecko) Version/9.0.2 Safari/601.3.9
Parse these user agents in bulk and tell me the browser, OS, and device type for each.
Does this user agent look like a crawler or bot? Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.96 Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
Example Answers and Tool Output
The text answers below are illustrative; exact wording depends on the model. JSON blocks are shortened examples, not current measurements. Location, ownership, contacts, and current-time fields can change.
Single IP lookup
Prompt: Locate 91.128.103.196 and give me the country, city, ASN, and local time.
Example answer: 91.128.103.196 is in Stockholm, Sweden. ASN is AS1257, operated by Tele2 Sverige AB. Timezone is Europe/Stockholm, local time was 2026-02-12 18:36:54.
{
"ip": "91.128.103.196",
"location": {
"country_name": "Sweden",
"state_prov": "Stockholms lan",
"city": "Stockholm"
},
"asn": {
"as_number": "AS1257",
"organization": "Tele2 Sverige AB",
"country": "SE"
},
"time_zone": {
"name": "Europe/Stockholm",
"current_time": "2026-02-12 18:36:54.401+0100"
}
}Time conversion
Prompt: Convert 2025-01-21 13:42:52 from DXB to LHR.
Example answer: 2025-01-21 13:42:52 in Dubai converts to 2025-01-21 09:42:52 in London. The difference is 4 hours.
{
"original_time": "2025-01-21 13:42:52",
"converted_time": "2025-01-21 09:42:52",
"diff_hour": 4,
"diff_min": 240
}Abuse contact
Prompt: Give me the abuse contact for 1.0.0.0.
Example answer: The abuse contact for 1.0.0.0 is IRT-APNICRANDNET-AU in Australia, covering route 1.0.0.0/24. Email: helpdesk@apnic.net.
{
"ip": "1.0.0.0",
"abuse": {
"route": "1.0.0.0/24",
"country": "AU",
"name": "IRT-APNICRANDNET-AU",
"address": "PO Box 3646, South Brisbane, QLD 4101, Australia",
"emails": ["helpdesk@apnic.net"]
}
}Error Codes
Tool failures return isError: true, readable text, and structuredContent.error with a redacted, length-limited message, category, retryability, and guidance:
Failure origin | Structured details |
HTTP error response received from the API |
|
Registered-schema rejection: wrong field type, missing required field, unknown parameter, or oversized batch |
|
Handler validation (such as dates or coordinate pairs), missing API key, or unavailable cached result |
|
Local request timeout |
|
Connection failure, invalid JSON, or invalid |
|
API returned an HTTP redirect |
|
Input validation uses the registered Zod schemas and the same structured error envelope as execution failures. Unknown tools and malformed MCP requests produce protocol errors. Retry guidance does not guarantee that a retry will succeed or be free: a local timeout can happen after the API processed a paid request. HTTP 429 is a credit/subscription limit, so immediate automatic retries are disabled; retry after credits become available.
The following table applies to HTTP errors actually received from the API:
Code | Meaning |
| Upstream API rejected the request parameters or input format |
| API key rejected, free plan calling a paid tool, or non-English |
| Resource not found (e.g., ASN does not exist) |
| Method or subscription restriction from the upstream API |
| POST body is larger than the upstream API allows |
| POST request is missing the required |
| Private, reserved, or bogon IP, including documentation addresses such as |
| Daily credit limit (free plan) or subscription/surcharge quota exceeded |
| Upstream API reports a client request or connection timeout |
| Upstream API server-side error |
Exact status codes can vary by endpoint and request mode. If an upstream endpoint returns a status outside this table, the server does not guess the cause. It passes the upstream status and message through with category: "undocumented_api_error" and adds guidance for the MCP client to explain the response as an undocumented upstream status without inventing a cause.
Bulk text preserves the API's per-item format. Structured results contain items in input order plus an errors list. Each failed item includes its zero-based input_index, original input, source, category, message, retryability, and guidance. An item status is present only if supplied by the API; message-only errors do not acquire an invented HTTP status. A mismatched result count returns a whole-call error rather than assigning unreliable input identifiers. Inspect every record; overall request success does not establish that every item succeeded, and successful items should not be retried.
How It Works
Your MCP client uses this server to call the IPGeolocation.io v3 APIs.
At runtime:
Your MCP client starts the server process.
The client reads the tool list.
When a prompt matches a tool, the client calls it.
The server validates arguments and returns a cached result or calls the API. It returns text content plus
structuredContent; all 17 tools advertise an output schema.
Result |
|
Single JSON lookup |
|
Public egress IP |
|
Bulk lookup |
|
Oversized success |
|
Whole-call failure |
|
Normal text responses keep the API's JSON format, or a plain IP string for get_my_ip. Oversized successful responses contain a page in both text and structured content.
Authenticated upstream requests send the API key in the x-ipgeolocation-api-key header. The key is not added to request URLs.
Server instructions and tool descriptions explain selection, costs, limits, and interpretation to the MCP client. Clients decide how to expose this guidance to their assistant. Returned WHOIS text, user agents, hostnames, and error messages are untrusted data and must not override those instructions. An omitted IP selector refers to the server machine's public egress IP, which can differ from the end user's IP. Security tools query IP intelligence; they do not invoke the separate browser-based Real-Time Proxy & VPN Detection.
lookup_company, lookup_currency, and lookup_network are wrappers around parts of the full IP lookup response. They exist as separate tools so MCP clients can discover them when a user only needs one piece of data.
Caching
The server stores cached responses in process memory and shares identical requests already running for the same API key. Sessions using the same key share the cache namespace; different keys use separate namespaces.
Cached data | Default expiry | Reads extend expiry? |
Normal tool response | 5 minutes after storage | No |
Complete pagination snapshot | 5 minutes of idle time | Yes, after each successful |
Both use IPGEOLOCATION_MCP_CACHE_TTL_MS (300000 ms by default). The cache holds up to 500 entries by default, shared by normal responses and page snapshots. This limits entry count, not total bytes or memory. A complete snapshot can be much larger than an individual page.
Expiry, eviction, or process restart can make cached data unavailable. get_cached_result then fails locally without refetching. Repeating the original lookup after a cache miss can consume credits again.
force_refresh: true starts a new upstream request, even if an identical request is running. Older requests cannot overwrite its cached result.
Cached: lookup_ip, bulk_lookup_ip, check_security, bulk_security_check, lookup_company, lookup_currency, lookup_network, parse_user_agent, bulk_parse_user_agent, lookup_asn, get_abuse_contact, get_astronomy_time_series
Always live (not cached): get_my_ip, get_timezone, convert_timezone, get_astronomy
Environment Variables
Variable | Required | Default | Description |
| Yes (most tools) | Your IPGeolocation.io API key | |
| No |
| Upstream deadline in ms, including response-body reading. Range: 1000-120000 |
| No |
| Normal-response TTL and page-snapshot idle TTL in ms. Range: 1000-3600000 |
| No |
| Maximum cached responses and page snapshots; not a memory-byte limit. Range: 10-5000 |
| No |
| Bulk input ceiling, also capped by |
| No |
| Bulk input/result item ceiling; nested arrays remain complete. Max: 50000 |
| No |
| Maximum UTF-8 bytes of a complete serialized tool result, including text and structured content. Oversized successes use cached pages; oversized errors shorten messages. Range: 10000-2000000 |
| No |
| Upper limit on error-message characters before truncation markers. The complete response byte budget can shorten messages further. Range: 200-50000 |
Bulk batches above the effective item limit are rejected before an upstream request, without using API credits. Raising only IPGEOLOCATION_MCP_MAX_BULK_ITEMS does not raise the effective limit; raise both item settings if larger batches are needed.
The response limit includes both text and structured content, JSON escaping, and UTF-8 encoding. Successful results retain every record and nested array through cached pages when needed. Oversized errors shorten only their messages, preserving their category, retryability, guidance, and any status.
Cached Result Pagination
get_cached_result costs 0 credits and never calls the API, including when its cursor is invalid, expired, evicted, or unavailable after a server restart. It accepts one required cursor, returned in page.cursor or page.next_cursor. Use the same server process and API key.
A large original lookup returns { "page": ... } instead of its normal data or items/errors. Each page contains:
Field | Meaning |
| Original lookup tool |
|
|
| Part of the complete original structured JSON result |
| Fragment position and full JSON length, in UTF-16 code units |
| Replay this page without repeating the lookup |
| Read the next page; absent on the final page |
| Idle expiry timestamp; successful reads extend the TTL, five minutes by default |
Read each next_cursor with get_cached_result, concatenate the json_fragment strings in offset order, and parse the joined JSON once. A fragment is not necessarily valid JSON on its own. This also handles a single record or string larger than one page. Bulk results reconstruct the complete { "items": [...], "errors": [...] }, preserving input identifiers and statuses. Single lookups reconstruct { "data": ... }.
let response = await client.callTool({ name: "bulk_lookup_ip", arguments: { ips } });
if (response.isError) throw new Error(response.content[0].text);
let complete = response.structuredContent;
if (complete.page) {
let json = "";
for (;;) {
const page = response.structuredContent.page;
json += page.json_fragment;
if (!page.next_cursor) break;
response = await client.callTool({
name: "get_cached_result", arguments: { cursor: page.next_cursor }
});
if (response.isError) throw new Error(response.content[0].text);
}
complete = JSON.parse(json);
}Use cursors to retrieve remaining data. The cache rules explain snapshot expiry, eviction, API-key isolation, and when a new lookup can consume credits.
Building from Source
git clone https://github.com/IPGeolocation/ipgeolocation-io-mcp.git
cd ipgeolocation-io-mcp
npm ci --ignore-scripts
npm run buildRun it directly:
node dist/cli.jsSet IPGEOLOCATION_API_KEY through your shell's private environment settings before running the command. The process waits for MCP messages on stdin; it does not display an interactive prompt.
Inspect with MCP Inspector:
npx @modelcontextprotocol/inspector node dist/cli.jsDocker
docker build -t ipgeolocation-mcp .
docker run --rm -i -e IPGEOLOCATION_API_KEY ipgeolocation-mcpSet IPGEOLOCATION_API_KEY in your private shell environment first. The image includes Node.js and runs as the unprivileged node user. Docker's -i flag keeps stdin open for MCP messages. Omit -t so the protocol uses ordinary stdin/stdout.
The image uses the official Node.js 24.22.1 Alpine 3.24 base with musl and runs the compiled server directly. The server has no native Node.js add-ons. npm and Yarn are available in the build stage; the runtime image contains Node.js and the installed production dependencies.
After building the image, configure a local-command MCP client with:
{
"mcpServers": {
"ipgeolocation": {
"command": "docker",
"args": ["run", "--rm", "-i", "-e", "IPGEOLOCATION_API_KEY", "ipgeolocation-mcp"],
"env": {
"IPGEOLOCATION_API_KEY": "<YOUR_API_KEY>"
}
}
}
}Testing
Client setup examples document configuration formats. Record GUI and operating-system installation checks separately from protocol, package, and Docker tests; see the release checklist.
npm test # full suite
npm run test:unit # unit tests only
npm run test:integration # integration tests onlyLive smoke tests use a real stdio MCP client and spend API credits. IPGEOLOCATION_FREE_KEY with npm run test:live:free checks the seven core tools, paid-feature restrictions, ownership/network fallbacks, and the observed bulk entitlement. It reports when bulk access differs from the documented paid-only policy. IPGEOLOCATION_PAID_KEY with npm run test:live:paid checks all 16 API tools, paid modules, structured validation errors, mixed valid/private bulk inputs, and the local cached-result reader. Testing a paid key does not verify free-plan entitlement restrictions.
After building, verify complete cached pagination with either key:
node tests/pagination.stdio.mjs free # uses IPGEOLOCATION_FREE_KEY
node tests/pagination.stdio.mjs paid # uses IPGEOLOCATION_PAID_KEYEach run makes one six-IP API request and checks the reported six credits. It compares the recovered records against a hash of the complete upstream response and verifies that page reads, replay, expiry, and process restart make no additional API calls. The test temporarily lowers the child server's response budget and cache TTL; your server configuration stays unchanged.
To check the same behavior in the image built above:
node tests/pagination.stdio.mjs free docker run --rm -i \
-e IPGEOLOCATION_API_KEY -e IPGEOLOCATION_MCP_MAX_RESPONSE_CHARS \
-e IPGEOLOCATION_MCP_CACHE_TTL_MS -e NODE_OPTIONS ipgeolocation-mcpTroubleshooting
Client uses an old tool after updating: Restart the server process and check its version in your client's MCP connection details. Compare it with the latest npm version. Rebuild source and Docker installations before restarting them.
API key not configured: Set IPGEOLOCATION_API_KEY in your client's server configuration. This local error has no HTTP status and makes no upstream request.
401 errors: The API rejected the key or requested capability. Check that the key is active and the plan supports the tool. Domain lookups in lookup_ip also require a paid plan.
423 errors: Use a public routable IP. Private/bogon addresses such as 10.0.0.1 and reserved documentation addresses such as 203.0.113.42 cannot be used as successful geolocation examples.
Local 504 timeouts: With source: "mcp_server", the request or response-body read exceeded the deadline. Check the connection or increase IPGEOLOCATION_REQUEST_TIMEOUT_MS (default: 15000 ms, max: 120000 ms). With source: "ipgeolocation_api", 504 is an HTTP response from the API.
Redirect blocked: The server received an unexpected HTTP redirect and stopped before forwarding credentials or request data. Do not retry automatically. Investigate the API endpoint or contact support with the sanitized error.
Cached result unavailable: The cursor belongs to another key or process, or the snapshot expired or was evicted. The failed page read made no API call. A new lookup can consume credits.
Client asks for an MCP URL: This package supplies a local stdio command. Use a client or host that can launch it; a remote-only connector needs a hosted MCP endpoint.
Pricing
For current plan details, credits, and pricing, see the IPGeolocation.io pricing page.
Links
License
Privacy Policy
API lookups send the requested inputs to IPGeolocation.io, which also receives the server machine's public egress IP. The server caches results in process memory. Your MCP client or hosting provider controls its own configuration and log storage. See the Security Policy for retention details and the IPGeolocation.io Privacy Policy for provider handling.
Available Tools
17 toolsbulk_lookup_ipBulk IP GeolocationARead-only
Read-only bulk IP lookup via POST /v3/ipgeo-bulk. Documented as paid-only; the upstream API determines plan access. Base IP data costs 1 credit per valid IP; security adds 2 and abuse adds 1. Selecting only security costs 2, only abuse costs 1, and security plus abuse without base data costs 3 per valid IP. This MCP server accepts up to 250 IPs per request. Larger batches are rejected before any API call. Complete results are returned directly or as cached pages. Oversized results contain page.next_cursor for complete retrieval through get_cached_result without another API call or additional credits.
The response covers location data or mixed IP data domains for multiple IPs or domains. Private, bogon, and malformed IPs are not billed. fields, excludes, lang, and include behave like lookup_ip for each item; this server also infers include modules from fields. bulk_security_check provides dedicated security-only batch responses.
| Name | Required | Description | Default |
|---|---|---|---|
| ips | Yes | Array of IPv4 and/or IPv6 addresses to look up. Minimum 1, maximum 250 in this MCP server. Domain names are also accepted. | |
| lang | No | Response language code (en, de, ru, ja, fr, cn, es, cs, it, ko, fa, pt). Defaults to en. | |
| fields | No | Comma-separated dot-path fields to return per IP (e.g. location.city,asn.organization). Reduces response size and can reduce credit cost when combined with include. Fields under security or abuse auto-add that module. location.accuracy_radius/confidence/locality auto-add geo_accuracy; location.dma_code auto-adds dma_code. Optional modules require a paid plan. | |
| include | No | Comma-separated extra modules to include per IP. Options: security (+2 credits/IP), abuse (+1 credit/IP), hostname, liveHostname, hostnameFallbackLive, user_agent, geo_accuracy, dma_code, or * for all (4 credits/IP total). | |
| excludes | No | Comma-separated dot-path fields to exclude per IP (e.g. currency,time_zone). | |
| force_refresh | No | Default false. When true, bypasses cached bulk geolocation data; a successful refresh makes a new upstream request and can consume credits. |
Output Schema
| Name | Required | Description |
|---|---|---|
| page | No | |
| error | No | Present when the whole tool call fails, with isError: true. |
| items | No | Present on success: complete API results in input order, including any per-item error messages. |
| errors | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint and openWorldHint; the description adds substantial context beyond them — per-IP credit math for base/security/abuse combinations, the hard 250-item pre-flight rejection, cached pagination via page.next_cursor, and that fetching oversized pages through get_cached_result costs no additional API call or credits. It even qualifies the read-only hint by noting force_refresh can consume credits.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Key facts (bulk scope, 250 limit, credit cost, pagination) are front-loaded and the alternative tool is named at the end. The credit-cost breakdown is somewhat repetitive, restating base/security/abuse pricing twice, and the sentence about 'location data or mixed IP data domains' is diffuse, but nothing is truly wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 6-parameter, credit-metered bulk tool with an output schema, the description covers everything an agent needs to call it correctly: input ceiling, rejection behavior, cost model, plan gating, pagination escape hatch, and sibling routing. Return-value structure is correctly left to the output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description earns more by adding cross-parameter meaning the schema only hints at — that it infers include modules from fields (e.g. security/abuse dot-paths auto-add modules) and that fields+include combinations can reduce credit cost. This tells the agent how to combine parameters economically, not just what each one is.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb, resource, and mode ('Read-only bulk IP lookup via POST /v3/ipgeo-bulk'), immediately separating it from the single-item lookup_ip sibling. It also names bulk_security_check as the dedicated alternative for security-only batches, so an agent can route without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete operating conditions: up to 250 IPs per request, larger batches rejected before any API call, paid-plan gating determined upstream, and private/bogon/malformed IPs not billed. It names bulk_security_check as the alternative for security-only work, but never explicitly says when to fall back to lookup_ip for single addresses, leaving that inference to the agent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
bulk_parse_user_agentBulk User-Agent ParserARead-only
Read-only bulk user-agent parsing via POST /v3/user-agent-bulk. Paid only. Cost: 1 credit per successful string. This MCP server accepts up to 250 explicit user-agent strings. Larger batches are rejected before any API call. Complete results are returned directly or as cached pages. Oversized results contain page.next_cursor for complete retrieval through get_cached_result without another API call or additional credits.
Returns one parsed object per string with user_agent_string, name, type, version, version_major, device, engine, and operating_system. uaStrings must be a non-empty array of exact user-agent strings; empty/null strings are rejected locally before any API call. parse_user_agent handles a single string. force_refresh bypasses cached data, makes a new upstream request, and can consume credits.
| Name | Required | Description | Default |
|---|---|---|---|
| uaStrings | Yes | Array of user-agent strings to parse. Minimum 1, maximum 250 in this MCP server. | |
| force_refresh | No | Default false. When true, bypasses cached bulk user-agent parsing data; a successful refresh makes a new upstream request and can consume credits. |
Output Schema
| Name | Required | Description |
|---|---|---|
| page | No | |
| error | No | Present when the whole tool call fails, with isError: true. |
| items | No | Present on success: complete API results in input order, including any per-item error messages. |
| errors | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the readOnlyHint/openWorldHint annotations: paid-only access at 1 credit per successful string, a hard 250-string ceiling enforced locally, local rejection of empty/null strings, caching plus page.next_cursor retrieval without another API call, and the credit cost of force_refresh. Credit consumption is a billing side effect, not a write, so it does not conflict with readOnlyHint.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the cost and size constraints an agent most needs, then return shape, then parameter notes. It is dense and mostly earns its length, though the 250 limit is stated twice and the return-field list duplicates the output schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers cost model, size limits, local validation, caching/pagination escape hatch, parameter flags, and the single-string alternative. With an output schema present the return-value enumeration is redundant but harmless; nothing an agent needs to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real meaning: uaStrings must be non-empty exact user-agent strings (not patterns), are validated locally, and force_refresh both bypasses the cache and incurs credits. It largely restates the schema's min/max bounds, which caps it below 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource (bulk user-agent parsing) plus the upstream endpoint POST /v3/user-agent-bulk. It explicitly distinguishes itself from the sibling parse_user_agent, which handles a single string, so an agent can choose between them without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names alternatives and the conditions selecting them: parse_user_agent for single strings, get_cached_result for oversized/paged results. It also tells the agent when force_refresh is warranted and what it costs, and warns that batches over 250 are rejected before any API call.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
bulk_security_checkBulk Security CheckARead-only
Read-only bulk security lookup via POST /v3/security-bulk. Paid only. Cost: 2 credits per valid IP. This MCP server accepts up to 250 IPs; private, bogon, and malformed IPs are not billed. Larger batches are rejected before any API call. Complete results are returned directly or as cached pages. Oversized results contain page.next_cursor for complete retrieval through get_cached_result without another API call or additional credits.
This endpoint is dedicated to security-only batches; bulk_lookup_ip with include=security provides security data together with geolocation or other IP domains. Returns one { ip, security } result per valid IP. fields/excludes accept security.* dot paths per item. force_refresh bypasses cached data, makes a new upstream request, and can consume credits.
| Name | Required | Description | Default |
|---|---|---|---|
| ips | Yes | Array of IPv4 and/or IPv6 addresses to check. Minimum 1, maximum 250 in this MCP server. | |
| fields | No | Comma-separated dot-path fields to return per IP (e.g. security.threat_score,security.is_vpn). Reduces response size. | |
| excludes | No | Comma-separated dot-path fields to exclude per IP (e.g. security.is_tor,security.is_cloud_provider). | |
| force_refresh | No | Default false. When true, bypasses cached bulk security data; a successful refresh makes a new upstream request and can consume credits. |
Output Schema
| Name | Required | Description |
|---|---|---|
| page | No | |
| error | No | Present when the whole tool call fails, with isError: true. |
| items | No | Present on success: complete API results in input order, including any per-item error messages. |
| errors | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint and openWorldHint; the description adds the economically critical behaviour: paid-only, 2 credits per valid IP, private/bogon/malformed IPs unbilled, and force_refresh causing a fresh upstream call that can consume credits. It also discloses paging via page.next_cursor that costs no extra credits. The only gap is that 'read-only' coexists with credit consumption without saying whether repeated identical calls are billed again when cache hits.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Cost, batch limit, and the sibling alternative are front-loaded in the first two sentences, with paging and parameter notes after. Dense and mostly waste-free, though the credit/caching story is split across two paragraphs and could be stated once.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Output schema exists, so return-shape explanation is unnecessary, and the description still covers billing model, batch ceiling, invalid-input handling, pagination, and sibling differentiation. For a 4-parameter, paid, open-world tool, an agent has everything needed to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description adds real value: fields/excludes operate on security.* dot paths per item, which tightens the broader schema examples, and it frames force_refresh as both a cache bypass and a billing event. Remaining parameter nuance (interaction of fields and excludes, invalid dot-path handling) is left unstated.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource+scope: 'Read-only bulk security lookup via POST /v3/security-bulk', and immediately distinguishes the tool from its nearest sibling by naming bulk_lookup_ip with include=security as the combined-domain alternative. An agent can pick correctly without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit routing rules: use this endpoint for security-only batches, use bulk_lookup_ip when security must be combined with geolocation or other domains, and use get_cached_result to page oversized results. It also states the hard exclusion boundary (batches over 250 rejected before any API call), which is a when-not condition.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
check_securityVPN/Proxy/Threat DetectionARead-only
Read-only security lookup via GET /v3/security. Paid only. Cost: 2 credits. This endpoint is dedicated to security and threat data; lookup_ip with include=security provides security data together with location, ASN/company, network, timezone, currency, or abuse.
Returns { ip, security } with threat_score, VPN, proxy, residential proxy, Tor, relay, anonymity, bot, spam, known attacker, and cloud-provider fields; provider names, confidence scores, and last_seen dates appear when available.
fields/excludes accept comma-separated security.* dot paths; ip is always returned. Threat scores and flags are indicators, not a safety guarantee; missing or unknown data is inconclusive. This queries IP intelligence, not the separate live browser detection API. force_refresh bypasses cached data, makes a new upstream request, and can consume credits.
| Name | Required | Description | Default |
|---|---|---|---|
| ip | No | IPv4 or IPv6 address to check. Omit to check the server's public egress IP. | |
| fields | No | Comma-separated dot-path fields to return (e.g. security.threat_score,security.is_vpn). Reduces response size. | |
| excludes | No | Comma-separated dot-path fields to exclude (e.g. security.is_tor,security.is_cloud_provider). | |
| force_refresh | No | Default false. When true, bypasses cached security data; a successful refresh makes a new upstream request and can consume credits. |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | No | Present on success: API result after field selection, redaction, and transport limits. |
| page | No | |
| error | No | Present on failure, with isError: true. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and openWorldHint, and the description adds the cost model (2 credits), the caching behavior of force_refresh and its credit implications, and an important interpretive caveat that threat flags are indicators rather than guarantees and that missing data is inconclusive. These are behavior facts an agent cannot get from annotations or schema alone.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the endpoint, read-only nature, cost, and differentiation before moving to return fields and caveats. Despite covering a lot, each sentence carries a distinct decision-relevant fact with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description does not need to define return values, yet it still summarizes the security object enough for the agent to know what it will receive. Cost, cache, refresh side effects, interpretive caveats, and sibling alternatives are all covered, leaving nothing an agent needs missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents all four parameters, establishing a baseline of 3. The description adds some value beyond this: it clarifies that fields/excludes take comma-separated security.* dot paths, that ip is always returned, and that force_refresh can consume credits on a new upstream request. That is a modest but real improvement over the schema text.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb, resource, and endpoint ("Read-only security lookup via GET /v3/security") and immediately distinguishes itself from lookup_ip with include=security. It also separates itself from the unrelated live browser detection API, so an agent can place it precisely among siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit routing rules: use this endpoint for dedicated security/threat data, use lookup_ip with include=security when location, ASN, network, timezone, currency, or abuse data is also wanted. It also states it is paid-only at 2 credits and is not the browser detection API — clear when-to-use and when-not-to-use guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
convert_timezoneTimezone ConversionARead-only
Read-only time conversion via GET /v3/timezone/convert. Works on free and paid plans. Cost: 1 credit. The conversion requires one source selector and one destination selector; get_timezone provides a single place's current time and metadata.
Source/destination selectors are tz_from/tz_to, location_from/location_to, iata_from/iata_to, icao_from/icao_to, locode_from/locode_to, or lat_from+long_from and lat_to+long_to. time is optional and must be yyyy-MM-dd HH:mm or yyyy-MM-dd HH:mm:ss. Returns original time, converted time, diff_hour, and diff_min.
| Name | Required | Description | Default |
|---|---|---|---|
| time | No | Time to convert in yyyy-MM-dd HH:mm or yyyy-MM-dd HH:mm:ss format. Defaults to current time. | |
| tz_to | No | Destination IANA timezone name (e.g. Asia/Tokyo). | |
| lat_to | No | Destination latitude. Use with long_to. | |
| iata_to | No | Destination 3-letter IATA airport code. | |
| icao_to | No | Destination 4-letter ICAO airport code. | |
| long_to | No | Destination longitude. Use with lat_to. | |
| tz_from | No | Source IANA timezone name (e.g. America/New_York). | |
| lat_from | No | Source latitude. Use with long_from. | |
| iata_from | No | Source 3-letter IATA airport code. | |
| icao_from | No | Source 4-letter ICAO airport code. | |
| locode_to | No | Destination 5-character UN/LOCODE. | |
| long_from | No | Source longitude. Use with lat_from. | |
| location_to | No | Destination city or address string. | |
| locode_from | No | Source 5-character UN/LOCODE. | |
| location_from | No | Source city or address string. |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | No | Present on success: API result after field selection, redaction, and transport limits. |
| page | No | |
| error | No | Present on failure, with isError: true. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint and openWorldHint; the description adds plan availability (free and paid), a concrete billing cost of 1 credit, the selector-pairing constraint, the accepted time formats and default, and the returned fields. That is substantive context an agent cannot get from the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with endpoint, cost, and the core selector rule — the right ordering. Slightly padded by enumerating every selector name, which the schema already lists, but each sentence still carries operational information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 15-parameter, zero-required tool this is complete: the pairing rule resolves the apparent ambiguity of all-optional params, cost/plan are disclosed, and an output schema exists so return values need no further explanation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, but the schema is a flat bag of 15 all-optional properties with no oneOf or required constraint. The description supplies the missing semantics: which parameters form interchangeable selector families (tz_*, location_*, iata_*, icao_*, locode_*, lat+long) and that exactly one from each side must be chosen. This is meaning beyond the schema, not repetition.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening states a specific verb (convert), resource (time/timezone), and the underlying endpoint GET /v3/timezone/convert, so it is immediately distinguishable from get_timezone, which is explicitly named as the single-place alternative.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It sets a hard structural rule for use: one source selector plus one destination selector are required. It also names get_timezone as the sibling for a single location's current time. It stops short of full when-not-to-use guidance (e.g. when to prefer a coordinate lookup over a city name), but the routing context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_abuse_contactAbuse Contact LookupARead-only
Read-only abuse contact lookup via GET /v3/abuse. Paid only. Cost: 1 credit. This endpoint is dedicated to abuse contact data; lookup_ip with include=abuse provides abuse data together with location, security, ASN/company, timezone, network, or currency.
Returns { ip, abuse } with route, country, name, organization, kind, address, emails, and phone_numbers for reporting abuse.
fields/excludes accept comma-separated abuse.* paths such as abuse.emails; ip is always returned. force_refresh bypasses cached data, makes a new upstream request, and can consume credits.
| Name | Required | Description | Default |
|---|---|---|---|
| ip | No | IPv4 or IPv6 address to get abuse contact for. Omit to use the server's public egress IP. | |
| fields | No | Comma-separated abuse fields to return (e.g. abuse.emails,abuse.organization). Reduces response size. | |
| excludes | No | Comma-separated abuse fields to exclude from response (e.g. abuse.phone_numbers,abuse.address). | |
| force_refresh | No | Default false. When true, bypasses cached abuse contact data; a successful refresh makes a new upstream request and can consume credits. |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | No | Present on success: API result after field selection, redaction, and transport limits. |
| page | No | |
| error | No | Present on failure, with isError: true. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint/openWorldHint annotations, it discloses credit cost, that force_refresh makes a new upstream request and can consume additional credits, that ip is always returned regardless of fields/excludes, and the return shape. This is exactly the behavioral context annotations cannot express.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose, cost, and the sibling alternative before details. Mild redundancy: the return-field list duplicates what the output schema already provides, and the raw route 'GET /v3/abuse' is not actionable for an agent.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only, zero-required-parameter lookup with a full output schema, the description covers cost, caching, filtering semantics, and fallback behavior. Nothing needed to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 100%, yet the description adds meaning: fields/excludes take comma-separated abuse.* paths (e.g. abuse.emails), and ip cannot be excluded. Slight overlap with the schema rather than pure added value, but the 'ip is always returned' invariant is genuinely new.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ('Read-only abuse contact lookup via GET /v3/abuse') and explicitly separates this tool from lookup_ip with include=abuse. An agent can distinguish it from all siblings without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It names the alternative (lookup_ip with include=abuse) and the condition that selects it — when you need abuse data together with location, security, ASN/company, timezone, network or currency. It also flags 'Paid only. Cost: 1 credit,' giving a clear cost-based selection rule.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_astronomyAstronomy DataARead-only
Read-only single-date astronomy lookup via GET /v3/astronomy. Works on free and paid plans. Cost: 1 credit. This endpoint covers one date or real-time sun/moon position; get_astronomy_time_series provides daily sunrise, moon, and twilight data across a date range.
Returns { location, astronomy } plus ip for IP/server-address lookups. astronomy includes date/current_time, sunrise/sunset, moonrise/moonset, twilight blocks, day_length, sun/moon position, distance, status, moon_phase, moon_illumination_percentage, and moon_angle.
Selector priority is lat/long, location, ip, then the server's public egress IP when no selector is provided. lat and long must be provided together; date must be YYYY-MM-DD; elevation must be 0-10000 meters. time_zone changes timestamp formatting to include full dates. lang only changes location fields; non-English lang is paid-only and returns 401 on free plans.
| Name | Required | Description | Default |
|---|---|---|---|
| ip | No | IPv4 or IPv6 address to get astronomy data for that IP's location. | |
| lat | No | Latitude coordinate. Highest priority. Must be used with long. | |
| date | No | Date in YYYY-MM-DD format. Defaults to today. | |
| lang | No | Response language for location fields in IP-based lookups (en, de, ru, ja, fr, cn, es, cs, it, ko, fa, pt, ar). Paid plans only. Free plan returns 401 for non-English language values. | |
| long | No | Longitude coordinate. Must be used with lat. | |
| location | No | City or address string (e.g. San Francisco, CA). | |
| elevation | No | Elevation in meters above sea level (0-10000). Affects sunrise/sunset calculations for higher accuracy. | |
| time_zone | No | IANA timezone name to express times in (e.g. America/New_York). If set, time fields include full date instead of just time. |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | No | Present on success: API result after field selection, redaction, and transport limits. |
| page | No | |
| error | No | Present on failure, with isError: true. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover readOnlyHint and openWorldHint, yet the description adds plan gating, per-call credit cost, the 401 failure mode for non-English lang on free plans, and the pairing constraint on lat/long. It also describes the response envelope ({ location, astronomy } plus ip for IP-based lookups), which goes well beyond what annotations declare.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with identity, endpoint, plan, and cost before the sibling comparison, then constraints. Slightly over-allocated to enumerating every field inside the astronomy object, which is partly redundant given an output schema exists, but the prose itself has no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an 8-parameter, zero-required, open-world lookup tool, the description covers selection logic, defaults, cost, plan restrictions, validation formats, and output shape. An agent could call it correctly from this text alone; nothing material is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the parameter baseline is 3; the description earns above that by adding the full selector precedence order and the implicit server-egress-IP fallback, which the schema does not state as a chain. It also restates date format, elevation bounds, time_zone formatting effect, and the free-plan 401 for non-English lang, giving genuine operational context beyond field descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('single-date astronomy lookup via GET /v3/astronomy') with the scope constraint ('one date or real-time sun/moon position'), and explicitly names the sibling get_astronomy_time_series as the range-based alternative. An agent can disambiguate from siblings without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes between this tool and get_astronomy_time_series on the single-date vs date-range axis, and states the selector priority chain (lat/long, location, ip, then server egress IP when nothing is provided). Plan eligibility and credit cost are also disclosed, so the when-to-use decision is fully supported.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_astronomy_time_seriesAstronomy Time SeriesARead-only
Read-only daily astronomy series via GET /v3/astronomy/timeSeries. Works on free and paid plans. Cost: 1 credit per request. This endpoint covers date ranges up to 90 days; get_astronomy provides one-date and real-time sun/moon data.
Returns { location, astronomy: [...] } with one daily item per date containing sunrise/sunset, moonrise/moonset, twilight blocks, day_length, sun/moon status, and moon_phase. Selector priority is lat/long, location, ip, then the server's public egress IP when no selector is provided.
dateStart and dateEnd are required YYYY-MM-DD values with a maximum 90-day span. lat and long must be provided together; elevation must be 0-10000 meters. time_zone changes timestamp formatting to include full dates. lang only changes location fields; non-English lang is paid-only and returns 401 on free plans. force_refresh bypasses cached data, makes a new upstream request, and can consume credits.
| Name | Required | Description | Default |
|---|---|---|---|
| ip | No | IPv4 or IPv6 address to get astronomy data for that IP's location. | |
| lat | No | Latitude coordinate. Highest priority. Must be used with long. | |
| lang | No | Response language for location fields in IP-based lookups (en, de, ru, ja, fr, cn, es, cs, it, ko, fa, pt, ar). Paid plans only. Free plan returns 401 for non-English languages. | |
| long | No | Longitude coordinate. Must be used with lat. | |
| dateEnd | Yes | End date in YYYY-MM-DD format. Required. Maximum range between dateStart and dateEnd is 90 days. | |
| location | No | City or address string (e.g. San Francisco, CA). | |
| dateStart | Yes | Start date in YYYY-MM-DD format. Required. Maximum range between dateStart and dateEnd is 90 days. | |
| elevation | No | Elevation in meters above sea level (0-10000). Affects sunrise/sunset calculations. | |
| time_zone | No | IANA timezone name to express times in (e.g. America/New_York). If set, time fields include full date instead of just time. | |
| force_refresh | No | Default false. When true, bypasses cached astronomy time-series data; a successful refresh makes a new upstream request and can consume credits. |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | No | Present on success: API result after field selection, redaction, and transport limits. |
| page | No | |
| error | No | Present on failure, with isError: true. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only cover readOnly/openWorld, but the description adds the operationally important traits: credit consumption, free-vs-paid gating with a specific 401 failure mode for non-English lang, force_refresh bypassing cache with new upstream request and possible credit spend, and the fallback to the server's egress IP when no selector is supplied. These are exactly the behaviors an agent cannot infer elsewhere.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose, endpoint, cost, and the sibling contrast, which is the right ordering. It loses a little to redundancy: the 90-day span cap is stated twice (once as scope, once per dateStart/dateEnd), and some parameter prose restates the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 10-parameter, quota-metered, plan-gated endpoint, the description covers selection, cost, plan limits, caching, and selector resolution. An output schema exists and the description still summarizes the return shape, so nothing needed for a correct call is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds value beyond it: the selector priority order (lat/long > location > ip > egress IP), the lat/long pairing rule, the 0-10000 elevation bound, and the note that lang only affects location fields. These are decision-relevant when an agent passes multiple selectors at once.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Read-only daily astronomy series") and even names the underlying endpoint, and it explicitly separates itself from the sibling get_astronomy ("provides one-date and real-time sun/moon data"). An agent can pick between the two without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly gives the selection condition (multi-day ranges up to 90 days) and points to the alternative for single-date and real-time use. It also states cost (1 credit/request) and plan eligibility up front, so the agent knows when the call is appropriate and what it costs.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_cached_resultRead Cached Result PageARead-only
Returns one page of a previously returned result using page.cursor or page.next_cursor. Costs 0 credits and never calls any upstream API, including on failure. The json_fragment strings concatenate in offset order into the complete original structuredContent JSON, including nested arrays and bulk item errors. The last page has no next_cursor. Cursors are scoped to the same API key and server process. Successful reads extend idle expiry by the configured cache TTL (five minutes by default); eviction or restart can remove a result. An unavailable cursor returns a local error and never starts another paid lookup.
| Name | Required | Description | Default |
|---|---|---|---|
| cursor | Yes | Opaque cursor returned in page.cursor or page.next_cursor. Retrieval requires the same server process and API key and does not repeat the original lookup. |
Output Schema
| Name | Required | Description |
|---|---|---|
| page | No | |
| error | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the readOnlyHint/openWorldHint annotations: costs 0 credits, never calls any upstream API (even on failure), cursors are scoped to the same API key and server process, success extends idle expiry by the cache TTL (5 min default), and eviction or restart can remove a result. It even specifies that an unavailable cursor returns a local error rather than triggering a paid lookup.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core operation, then layers cost, reconstruction, expiry, and failure semantics. Several clauses are dense (json_fragment concatenation, expiry extension), but each carries actionable information rather than filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Complete for a single-parameter, output-schema-backed cache reader: it discloses cost, ordering/reconstruction of json_fragment, termination, scope, lifetime, and failure modes. An agent has everything needed to decide whether and how to call it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the schema already documents the cursor pattern and origin, so the baseline is 3. The description adds real meaning by explaining the cursor's provenance (page.cursor/page.next_cursor), its API-key/server-process scoping, and that reuse does not repeat the original lookup.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Returns one page of a previously returned result') with the exact mechanism ('using page.cursor or page.next_cursor'). It is trivially distinguishable from the lookup_* siblings because it operates on cached output rather than performing upstream lookups.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is clearly framed as pagination continuation using a previously returned cursor, and the termination condition ('last page has no next_cursor') plus failure behavior give concrete context. It stops short of explicitly naming when to prefer this over the sibling lookups, but the implied scope is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_my_ipGet My IP AddressARead-only
Returns the public IP address of the machine running this MCP server via GET /v3/getip. Takes no input parameters and requires no API key, account, or credits. The response is a plain IP address string, not geolocation data; lookup_ip provides location, ASN, timezone, currency, security, and abuse data.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| ip | No | |
| page | No | |
| error | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes beyond the readOnlyHint/openWorldHint annotations by disclosing that no API key, account, or credits are required – auth/billing context an agent cannot infer from annotations – and by specifying the response is a plain IP string. It does not cover rate limits or failure modes, but the added auth and response-shape detail is real value.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences that each carry a distinct payload: what it returns, what it costs/requires, and how it differs from the nearest alternative. Purpose is front-loaded and nothing is padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-argument, read-only lookup with an output schema, the description supplies everything an agent needs: identity of the resource, absence of required credentials, return shape, and sibling routing. No behavioral dimension is left unaddressed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline is 4 and there is nothing further to document. The description reinforces this with 'takes no input parameters,' which matches additionalProperties: false in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Returns the public IP address of the machine running this MCP server') and even names the underlying route GET /v3/getip. It explicitly distinguishes itself from sibling lookup_ip by scope, so an agent can separate the two without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives the selecting condition directly: use this for the caller's own public IP; use lookup_ip when location, ASN, timezone, currency, security, or abuse data is needed. It also pre-empts a false assumption by stating the result is not geolocation, which is the main reason an agent would pick the wrong sibling.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_timezoneTimezone LookupARead-only
Read-only timezone lookup via GET /v3/timezone. Works on free and paid plans. Cost: 1 credit. This endpoint provides current local time and metadata for one place, IP, airport, UN/LOCODE, or IANA timezone; convert_timezone provides source-to-destination conversion.
Returns { time_zone } plus selector context such as location, airport, city, or ip. time_zone includes the zone name, current time, UTC offsets, date/time variants, abbreviations, and DST status/transition fields when available.
Selector priority is tz, lat/long, location, ip, iata_code, icao_code, then lo_code. lat and long must be provided together. lang only changes location fields; non-English lang is paid-only and returns 401 on free plans.
| Name | Required | Description | Default |
|---|---|---|---|
| ip | No | IPv4 or IPv6 address to get timezone for. | |
| tz | No | IANA timezone name (e.g. America/New_York, Europe/London). Highest priority if multiple params provided. | |
| lat | No | Latitude coordinate. Must be used together with long. | |
| lang | No | Response language for location fields in IP-based lookups (en, de, ru, ja, fr, cn, es, cs, it, ko, fa, pt, ar). Paid plans only. Free plan returns 401 for non-English language values. | |
| long | No | Longitude coordinate. Must be used together with lat. | |
| lo_code | No | 5-character UN/LOCODE (e.g. DEBER, USNYC). | |
| location | No | City or address string (e.g. London, UK). | |
| iata_code | No | 3-letter IATA airport code (e.g. JFK, LHR). Returns airport details in the response. | |
| icao_code | No | 4-letter ICAO airport code (e.g. KJFK, EGLL). Returns airport details in the response. |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | No | Present on success: API result after field selection, redaction, and transport limits. |
| page | No | |
| error | No | Present on failure, with isError: true. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint/openWorldHint, yet the description adds cost (1 credit), plan gating with the specific 401 failure mode, selector priority ordering when multiple params are supplied, and the lat/long pairing constraint. That is substantive behavior beyond structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose and sibling disambiguation, and the priority/constraint sentences earn their space. The paragraph detailing time_zone sub-fields is partially redundant given an output schema exists, which costs a point on tightness.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 9-parameter, all-optional selector tool, the description covers plan gating, cost, precedence, pairing constraints, and the shape of the union return. Nothing an agent needs in order to pick a selector and call correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description adds the precedence chain (tz, lat/long, location, ip, iata_code, icao_code, lo_code) and clarifies that lang only affects location fields rather than the whole response. These are semantics the schema does not state in one place.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Read-only timezone lookup via GET /v3/timezone') and enumerates the accepted inputs (place, IP, airport, UN/LOCODE, IANA timezone). It explicitly separates itself from the nearest sibling: 'convert_timezone provides source-to-destination conversion.'
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear operating context: works on free and paid plans, costs 1 credit, and lang is paid-only (401 on free). It names convert_timezone as the alternative for conversion, but does not address how this differs from the sibling lookup_ip, which plausibly also yields timezone data.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lookup_asnASN DetailsARead-only
Read-only ASN enrichment via GET /v3/asn. Paid only. Cost: 1 credit. Queries accept asn or ip, with asn taking priority. The response covers ASN relationships, route prefixes, allocation details, and WHOIS; lookup_ip provides basic ASN data together with geolocation.
Returns { asn } core fields plus included peers, downstreams, upstreams, routes, or whois_response. include accepts those five values. fields/excludes accept full asn.* paths or root-relative paths such as upstreams.as_number. fields automatically enables required optional datasets; excludes alone never requests extra datasets. force_refresh bypasses cached data, makes a new upstream request, and can consume credits.
| Name | Required | Description | Default |
|---|---|---|---|
| ip | No | IPv4 or IPv6 address to find the ASN for. Used only if asn is not provided. | |
| asn | No | AS number to look up (e.g. AS13335 or just 13335). Takes priority over ip if both are provided. | |
| fields | No | Comma-separated dot-path fields to return (e.g. asn.as_number,asn.organization or upstreams.as_number). Paths can be full (asn.upstreams.as_number) or relative to the asn root (upstreams.as_number). This server auto-adds optional datasets referenced by fields; excludes alone does not enable them. | |
| include | No | Comma-separated extra data to include: peers, downstreams, upstreams, routes, whois_response. No additional credit cost. | |
| excludes | No | Comma-separated dot-path fields to exclude (e.g. asn.date_allocated,asn.rir or upstreams.description). Paths can be full or relative to the asn root. | |
| force_refresh | No | Default false. When true, bypasses cached ASN data; a successful refresh makes a new upstream request and can consume credits. |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | No | Present on success: API result after field selection, redaction, and transport limits. |
| page | No | |
| error | No | Present on failure, with isError: true. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond readOnlyHint/openWorldHint by disclosing that the tool is paid, costs 1 credit, that force_refresh issues a new upstream request and can consume additional credits, and that cached data is bypassed. It also documents the non-obvious interaction where fields auto-enables optional datasets but excludes does not.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with cost and access constraints, then inputs, then output shape — a sensible order. The return-shape sentence is somewhat dense and partially redundant given an output schema exists, but no sentence is pure filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers cost, caching, input precedence, dataset inclusion rules, and result fields for a zero-required-parameter enrichment tool. The enumeration of response fields is largely redundant with the existing output schema, so it is complete but not maximally efficient.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so per-parameter meaning is already covered; the description's added value is the cross-parameter rule that fields implicitly requests datasets while excludes never does, plus the asn-over-ip priority. That is real semantics beyond the schema, though much of the rest restates it.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Read-only ASN enrichment via GET /v3/asn') and immediately scopes it against the nearest sibling by noting that lookup_ip returns basic ASN data plus geolocation. An agent can pick between the two without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names the alternative (lookup_ip) and the tradeoff that selects it, and clarifies precedence between the asn and ip inputs. It stops short of an explicit 'do not use this when…' exclusion, but the routing context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lookup_companyCompany/Organization LookupARead-only
Read-only ownership lookup via GET /v3/ipgeo. Company details require a paid plan; free plans return basic ASN ownership only. Cost: 1 credit. This response is limited to company and ASN ownership; lookup_ip can return ownership together with location, security, abuse, network, timezone, or currency.
Returns { company, asn }: company name/type/domain plus ASN allocation fields when available. ip omitted means the server's public egress IP. force_refresh bypasses cached data, makes a new upstream request, and can consume credits.
| Name | Required | Description | Default |
|---|---|---|---|
| ip | No | IPv4 or IPv6 address to look up. Omit to check the server's public egress IP. | |
| force_refresh | No | Default false. When true, bypasses cached ownership data; a successful refresh makes a new upstream request and can consume credits. |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | No | Present on success: API result after field selection, redaction, and transport limits. |
| page | No | |
| error | No | Present on failure, with isError: true. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and openWorldHint, but the description adds real behavioral context: credit cost per call, the paid-plan gating that degrades results on free plans, caching behavior, and the fact that force_refresh makes a new upstream request that can consume credits. That is exactly the kind of cost/side-effect disclosure annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Content is front-loaded with the purpose, then constraints, then the sibling differentiation, then return shape — a sensible ordering. It is slightly dense, and the return-shape sentence partially duplicates the output schema, but every sentence still carries usable information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-required-parameter lookup with an output schema present, the description covers purpose, cost, plan gating, caching side effects, and a summary of the returned { company, asn } shape. Nothing an agent needs in order to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both parameters are already fully documented, including the omitted-ip egress behavior and the force_refresh credit caveat. The description restates these facts rather than adding syntax or edge cases beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource (read-only ownership lookup) and names the endpoint (GET /v3/ipgeo). It explicitly contrasts itself with lookup_ip, so the agent can distinguish the two without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names the alternative (lookup_ip) and the condition that selects it — when ownership is needed together with location, security, abuse, network, timezone, or currency. It also states the plan prerequisite (paid plan for company details, free plans get ASN ownership only) and the 1-credit cost, so an agent knows both when to call it and what constraints apply.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lookup_currencyCurrency and Country MetadataARead-only
Read-only currency and country metadata lookup via GET /v3/ipgeo. Works on free and paid plans. Cost: 1 credit per successful lookup.
Returns { currency, country_metadata }: currency code/name/symbol plus country calling_code, tld, and languages. ip selects the IP used to derive country and currency; omit it for the server machine's public egress IP. force_refresh bypasses cached data, makes a new upstream request, and can consume credits.
This response is limited to currency and country metadata. lookup_ip can return these fields together with other IP data.
| Name | Required | Description | Default |
|---|---|---|---|
| ip | No | IPv4 or IPv6 address whose country determines the returned currency and country metadata. Omit to use the server's public egress IP. | |
| force_refresh | No | Default false. When true, bypasses cached currency/country data; a successful refresh makes a new upstream request and can consume credits. |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | No | Present on success: API result after field selection, redaction, and transport limits. |
| page | No | |
| error | No | Present on failure, with isError: true. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark this read-only and open-world, and the description goes well beyond them: 1 credit per successful lookup, cache behavior, that force_refresh triggers a new upstream request and can consume credits, and the default egress-IP behavior when ip is omitted. These are exactly the cost and side-effect facts an agent cannot get from structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose, cost, and return shape, then the scoping note against lookup_ip — a sensible order. The return-value sentence duplicates what the output schema already provides, which is the one piece that doesn't fully earn its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 2-param, zero-required, read-only lookup with a full output schema and 100% schema coverage, the description covers cost, caching, default behavior, and sibling routing. Nothing an agent needs to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, and the description adds real meaning by framing ip as the selector of which country/currency is derived and by spelling out the credit implication of force_refresh. It largely restates the schema's own parameter text, so it adds value but not much new syntax or edge-case guidance.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ("read-only currency and country metadata lookup") plus the underlying endpoint, and explicitly differentiates from the sibling lookup_ip. An agent can distinguish this from lookup_ip, lookup_network, and lookup_company without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It names the alternative (lookup_ip) and the exact condition that selects it — when you want these fields alongside other IP data. It also states plan availability, credit cost per lookup, and the credit consequence of force_refresh, so the agent can reason about when to call this versus alternatives and when to avoid the refresh flag.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lookup_ipIP Geolocation LookupARead-only
Read-only unified IP lookup via GET /v3/ipgeo. Base IP data costs 1 credit; security adds 2 and abuse adds 1. Selecting only security costs 2, only abuse costs 1, and security plus abuse without base data costs 3 credits. The unified response can cover multiple data domains for one IP or domain: location, company/ASN, network, timezone, currency, security, abuse, user_agent, hostname, geo_accuracy, and dma_code.
Returns root IP/domain data plus selected objects such as location, country_metadata, currency, asn, network, company, time_zone, security, abuse, user_agent, or hostname. geo_accuracy adds location.accuracy_radius, location.confidence, and location.locality; dma_code adds location.dma_code. Free plans support core location, country_metadata, currency, time_zone, basic ASN, fields, and excludes; paid plans add domain lookup, company, network, extended ASN, non-English lang, and include modules.
ip omitted means the server's public egress IP. IP location is an estimate, not a precise device position. fields/excludes accept comma-separated dot paths; ip is always returned and unknown excludes do not error. Explicit include tokens keep their modules even when fields omits them; fields can select their nested paths and excludes can remove nested paths. A root named by fields or an explicit include cannot be excluded as a whole. include=* follows fields/excludes without this explicit-token protection. This server auto-adds include modules referenced by fields, including optional location fields. lookup_asn provides ASN relationships, routes, and WHOIS; check_security and get_abuse_contact provide dedicated security and abuse responses.
| Name | Required | Description | Default |
|---|---|---|---|
| ip | No | IPv4 address, IPv6 address, or domain name to look up. Domain lookups require a paid plan. Omit to use the server's public egress IP. | |
| lang | No | Response language code (en, de, ru, ja, fr, cn, es, cs, it, ko, fa, pt). Paid plans only. Free plan returns a 401 error if you pass any value other than en. Defaults to en. | |
| fields | No | Comma-separated dot-path fields to return (e.g. location.city,asn.organization). Works on all plans including free. Reduces response size and can reduce credit cost when combined with include. Fields under security or abuse auto-add that include module. location.accuracy_radius/confidence/locality auto-add geo_accuracy; location.dma_code auto-adds dma_code. Those optional modules require a paid plan. | |
| include | No | Comma-separated extra modules to include in the response. Paid plans only. Options: security (+2 credits), abuse (+1 credit), hostname, liveHostname, hostnameFallbackLive, user_agent, geo_accuracy, dma_code, or * for all (4 credits total). Free plan cannot use this parameter. | |
| excludes | No | Comma-separated dot-path fields to exclude from response (e.g. currency,location.continent_code). Works on all plans including free. | |
| force_refresh | No | Default false. When true, bypasses cached lookup_ip data; a successful refresh makes a new upstream request and can consume credits. |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | No | Present on success: API result after field selection, redaction, and transport limits. |
| page | No | |
| error | No | Present on failure, with isError: true. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover readOnly/openWorld, but the description adds a lot beyond them: a granular credit cost model per module, free-plan vs paid-plan capability split (free plan rejects include and non-English lang with 401), cache-bypass semantics for force_refresh consuming credits, and the caveat that IP location is an estimate rather than a device position. These are exactly the behaviors an agent needs before invoking a metered lookup.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core is front-loaded and the cost model comes early, which is right. But the description repeats the module list twice ('location, company/ASN, network, timezone, currency, security, abuse, user_agent, hostname, geo_accuracy, dma_code' then 'location, country_metadata, currency, asn, network, company, time_zone, security, abuse, user_agent, or hostname'), and the credit arithmetic is written out in repeated, laborious sentences that restate what the include schema already documents.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a metered, plan-gated, field-selective lookup, the description covers cost, plan tiers, field/exclude interaction, caching, and the accuracy caveat, so an agent can call it correctly. An output schema exists, yet the description still spends several sentences enumerating returned objects, which is redundant rather than missing — the completeness gap is small.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% so the baseline is 3, but the description contributes real semantics beyond the schema: explicit include tokens keep their modules even when fields omits them, include=* loses that protection, a root named by fields or an explicit include cannot be wholly excluded, and the server auto-adds include modules referenced by fields. Minor drawback is that this is buried in one dense paragraph rather than tied to parameter names.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Read-only unified IP lookup via GET /v3/ipgeo') and frames the tool as the aggregate entry point covering location, company/ASN, network, security, abuse, etc. It explicitly names the sibling tools (lookup_asn, check_security, get_abuse_contact) that serve narrower purposes, so an agent can distinguish it without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The closing sentence routes the agent to alternatives: 'lookup_asn provides ASN relationships, routes, and WHOIS; check_security and get_abuse_contact provide dedicated security and abuse responses.' Combined with the free-vs-paid plan restrictions, a caller knows the main conditions. It never states an explicit exclusion such as 'do not use this if you only need ASN data', so it falls short of a full 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lookup_networkNetwork/Routing InfoARead-only
Read-only network lookup via GET /v3/ipgeo. Network details require a paid plan. Cost: 1 credit. Returns { network } with route CIDR prefix, connection_type, and is_anycast. If the API omits network data, returns a local error without inventing an HTTP status; credits may already have been used.
ip omitted means the server's public egress IP. force_refresh bypasses cached data, makes a new upstream request, and can consume credits. This response is limited to network data; lookup_ip can return network data together with location, ASN/company, timezone, currency, security, or abuse.
| Name | Required | Description | Default |
|---|---|---|---|
| ip | No | IPv4 or IPv6 address to look up. Omit to check the server's public egress IP. | |
| force_refresh | No | Default false. When true, bypasses cached network data; a successful refresh makes a new upstream request and can consume credits. |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | No | Present on success: API result after field selection, redaction, and transport limits. |
| page | No | |
| error | No | Present on failure, with isError: true. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well past the readOnlyHint/openWorldHint annotations: discloses paid-plan gating, a 1-credit cost, that force_refresh consumes credits, and — importantly — that an omitted network payload returns a local error rather than a fabricated HTTP status while credits may already have been spent. That partial-failure/irreversible-cost disclosure is exactly the kind of context annotations can't carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the endpoint and cost, then scoped to the return shape, then to parameter behavior and the sibling alternative. Dense and purposeful, though the duplicated cost warning about credits across both paragraphs is slightly redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, yet the description still names the returned object and its fields, plus plan gating, credit accounting, cache semantics, and an error-path contract. Nothing an agent needs to decide and call correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and both parameter descriptions already state the egress-IP default and the cache-bypass/credit behavior, so the description largely restates what the schema provides. The credit-consumption angle reinforces the semantics but adds no syntax or format the agent couldn't already read.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb+resource ("Read-only network lookup via GET /v3/ipgeo") and pins the return surface ({ network } with route CIDR, connection_type, is_anycast). The closing sentence explicitly distinguishes it from lookup_ip, which returns network data plus a much broader field set.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Covers the key selection conditions: use this when only network data is needed, use lookup_ip when location/ASN/security/abuse data is also wanted, and it explains the two call modes (omitted ip = egress IP, force_refresh = new upstream request). Exclusions and cost tradeoffs are both stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
parse_user_agentUser-Agent ParserARead-only
Read-only custom user-agent parsing via POST /v3/user-agent. Paid only for POST payload parsing. Cost: 1 credit per successful string. Parses only the explicit uaString value; it cannot read caller headers or transport metadata.
Returns { user_agent_string, name, type, version, version_major, device, engine, operating_system }. Type fields can identify desktop/mobile clients, robots, malformed or scripted strings, anonymized strings, or unknown values. uaString must be the exact non-empty user-agent string; empty/null strings are rejected locally before any API call. force_refresh bypasses cached data, makes a new upstream request, and can consume credits. bulk_parse_user_agent handles multiple strings.
| Name | Required | Description | Default |
|---|---|---|---|
| uaString | Yes | The user-agent string to parse (e.g. Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36). | |
| force_refresh | No | Default false. When true, bypasses cached user-agent parsing data; a successful refresh makes a new upstream request and can consume credits. |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | No | Present on success: API result after field selection, redaction, and transport limits. |
| page | No | |
| error | No | Present on failure, with isError: true. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare read-only and open-world, but the description adds the material business behavior: 1 credit per successful string, credits only charged for POST payload parsing, force_refresh triggers a new upstream request that can consume credits, and empty/null input is rejected locally before any API call. Cost and validation semantics are non-obvious and would otherwise cause surprise charges.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose, scope, and cost, then return shape, then edge cases. Dense but mostly earned; a couple of clauses (e.g. the type-field enumeration) sit on the edge of what an agent needs before invoking, keeping it just below top marks.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite an output schema existing, the description names the return fields and their interpretive use (type can flag robots, malformed, anonymized, unknown), plus validation, cost, and sibling routing. Nothing an agent needs to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds meaning beyond the schema: uaString must be the exact non-empty string and is validated locally before any call, and force_refresh is tied to credit consumption and cache bypass. These are reinforcing operational constraints rather than new syntax, so 4 rather than 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource (parses a user-agent string via POST /v3/user-agent) and immediately scopes it against the bulk sibling. An agent can distinguish it from bulk_parse_user_agent without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly limits scope ("Parses only the explicit uaString value; it cannot read caller headers or transport metadata") and routes multi-string use to bulk_parse_user_agent. This is exactly the when-to-use / when-not guidance an agent needs to avoid misuse.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
15 tool updates
v2.0.3- Changed
bulk_lookup_ip2 fields changed- removed
Output schema / properties / items / items / additionalProperties / anyOfRemoved value: -[ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - }, - { - "type": "array" - }, - { - "type": "object" - } -] - added
Output schema / properties / items / items / additionalProperties / typeAdded value: +[ + "null", + "boolean", + "number", + "string", + "array", + "object" +]
- Changed
bulk_parse_user_agent2 fields changed- removed
Output schema / properties / items / items / additionalProperties / anyOfRemoved value: -[ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - }, - { - "type": "array" - }, - { - "type": "object" - } -] - added
Output schema / properties / items / items / additionalProperties / typeAdded value: +[ + "null", + "boolean", + "number", + "string", + "array", + "object" +]
- Changed
bulk_security_check2 fields changed- removed
Output schema / properties / items / items / additionalProperties / anyOfRemoved value: -[ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - }, - { - "type": "array" - }, - { - "type": "object" - } -] - added
Output schema / properties / items / items / additionalProperties / typeAdded value: +[ + "null", + "boolean", + "number", + "string", + "array", + "object" +]
- Changed
check_security2 fields changed- removed
Output schema / properties / data / additionalProperties / anyOfRemoved value: -[ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - }, - { - "type": "array" - }, - { - "type": "object" - } -] - added
Output schema / properties / data / additionalProperties / typeAdded value: +[ + "null", + "boolean", + "number", + "string", + "array", + "object" +]
- Changed
convert_timezone2 fields changed- removed
Output schema / properties / data / additionalProperties / anyOfRemoved value: -[ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - }, - { - "type": "array" - }, - { - "type": "object" - } -] - added
Output schema / properties / data / additionalProperties / typeAdded value: +[ + "null", + "boolean", + "number", + "string", + "array", + "object" +]
- Changed
get_abuse_contact2 fields changed- removed
Output schema / properties / data / additionalProperties / anyOfRemoved value: -[ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - }, - { - "type": "array" - }, - { - "type": "object" - } -] - added
Output schema / properties / data / additionalProperties / typeAdded value: +[ + "null", + "boolean", + "number", + "string", + "array", + "object" +]
- Changed
get_astronomy2 fields changed- removed
Output schema / properties / data / additionalProperties / anyOfRemoved value: -[ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - }, - { - "type": "array" - }, - { - "type": "object" - } -] - added
Output schema / properties / data / additionalProperties / typeAdded value: +[ + "null", + "boolean", + "number", + "string", + "array", + "object" +]
- Changed
get_astronomy_time_series2 fields changed- removed
Output schema / properties / data / additionalProperties / anyOfRemoved value: -[ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - }, - { - "type": "array" - }, - { - "type": "object" - } -] - added
Output schema / properties / data / additionalProperties / typeAdded value: +[ + "null", + "boolean", + "number", + "string", + "array", + "object" +]
- Changed
get_timezone2 fields changed- removed
Output schema / properties / data / additionalProperties / anyOfRemoved value: -[ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - }, - { - "type": "array" - }, - { - "type": "object" - } -] - added
Output schema / properties / data / additionalProperties / typeAdded value: +[ + "null", + "boolean", + "number", + "string", + "array", + "object" +]
- Changed
lookup_asn2 fields changed- removed
Output schema / properties / data / additionalProperties / anyOfRemoved value: -[ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - }, - { - "type": "array" - }, - { - "type": "object" - } -] - added
Output schema / properties / data / additionalProperties / typeAdded value: +[ + "null", + "boolean", + "number", + "string", + "array", + "object" +]
- Changed
lookup_company2 fields changed- removed
Output schema / properties / data / additionalProperties / anyOfRemoved value: -[ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - }, - { - "type": "array" - }, - { - "type": "object" - } -] - added
Output schema / properties / data / additionalProperties / typeAdded value: +[ + "null", + "boolean", + "number", + "string", + "array", + "object" +]
- Changed
lookup_currency2 fields changed- removed
Output schema / properties / data / additionalProperties / anyOfRemoved value: -[ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - }, - { - "type": "array" - }, - { - "type": "object" - } -] - added
Output schema / properties / data / additionalProperties / typeAdded value: +[ + "null", + "boolean", + "number", + "string", + "array", + "object" +]
- Changed
lookup_ip2 fields changed- removed
Output schema / properties / data / additionalProperties / anyOfRemoved value: -[ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - }, - { - "type": "array" - }, - { - "type": "object" - } -] - added
Output schema / properties / data / additionalProperties / typeAdded value: +[ + "null", + "boolean", + "number", + "string", + "array", + "object" +]
- Changed
lookup_network2 fields changed- removed
Output schema / properties / data / additionalProperties / anyOfRemoved value: -[ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - }, - { - "type": "array" - }, - { - "type": "object" - } -] - added
Output schema / properties / data / additionalProperties / typeAdded value: +[ + "null", + "boolean", + "number", + "string", + "array", + "object" +]
- Changed
parse_user_agent2 fields changed- removed
Output schema / properties / data / additionalProperties / anyOfRemoved value: -[ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - }, - { - "type": "array" - }, - { - "type": "object" - } -] - added
Output schema / properties / data / additionalProperties / typeAdded value: +[ + "null", + "boolean", + "number", + "string", + "array", + "object" +]
17 tool updates
v2.0.1- Changed
bulk_lookup_ip5 fields changed- added
Input schema / additionalPropertiesAdded value: +false - changed
Input schema / properties / fields / descriptionPrevious value: -"Comma-separated dot-path fields to return per IP (e.g. location.city,asn.organization). Reduces response size and can reduce credit cost when combined with include. If fields reference include-only modules (for example security.* or abuse.*), this server auto-adds required include modules."New value: +"Comma-separated dot-path fields to return per IP (e.g. location.city,asn.organization). Reduces response size and can reduce credit cost when combined with include. Fields under security or abuse auto-add that module. location.accuracy_radius/confidence/locality auto-add geo_accuracy; location.dma_code auto-adds dma_code. Optional modules require a paid plan." - changed
Input schema / properties / ips / descriptionPrevious value: -"Array of IPv4 and/or IPv6 addresses to look up. Minimum 1, maximum 1,000 in this MCP server. Domain names are also accepted."New value: +"Array of IPv4 and/or IPv6 addresses to look up. Minimum 1, maximum 250 in this MCP server. Domain names are also accepted." - changed
Input schema / properties / ips / maxItemsPrevious value: -1000New value: +250 - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "error": { + "additionalProperties": false, + "description": "Present when the whole tool call fails, with isError: true.", + "properties": { + "assistant_guidance": { + "type": "string" + }, + "category": { + "type": "string" + }, + "documented_status": { + "type": "boolean" + }, + "explanation_hint": { + "type": "string" + }, + "guidance": { + "type": "string" + }, + "message": { + "type": "string" + }, + "retryable": { + "type": "boolean" + }, + "source": { + "enum": [ + "mcp_server", + "ipgeolocation_api" + ], + "type": "string" + }, + "status": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "required": [ + "source", + "category", + "message", + "retryable", + "guidance", + "assistant_guidance" + ], + "type": "object" + }, + "errors": { + "items": { + "additionalProperties": false, + "properties": { + "category": { + "const": "upstream_item", + "type": "string" + }, + "guidance": { + "type": "string" + }, + "input": { + "type": "string" + }, + "input_index": { + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "message": { + "type": "string" + }, + "retryable": { + "type": "boolean" + }, + "source": { + "const": "ipgeolocation_api", + "type": "string" + }, + "status": { + "description": "Present only when the API supplied an item HTTP status.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "required": [ + "input_index", + "input", + "source", + "category", + "message", + "retryable", + "guidance" + ], + "type": "object" + }, + "type": "array" + }, + "items": { + "description": "Present on success: complete API results in input order, including any per-item error messages.", + "items": { + "additionalProperties": { + "anyOf": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + }, + { + "type": "array" + }, + { + "type": "object" + } + ] + }, + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "type": "array" + }, + "page": { + "additionalProperties": false, + "properties": { + "cursor": { + "description": "Opaque cursor returned in page.cursor or page.next_cursor. Retrieval requires the same server process and API key and does not repeat the original lookup.", + "maxLength": 80, + "pattern": "^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}:\\d{1,16}$", + "type": "string" + }, + "expires_at": { + "description": "ISO timestamp for idle expiry. Successful page reads extend the cache TTL; eviction or process restart can also remove the result.", + "type": "string" + }, + "format": { + "const": "structuredContent_json", + "type": "string" + }, + "json_fragment": { + "description": "JSON fragment of the original structuredContent. Fragments concatenate in offset order into the complete JSON, including bulk items and errors.", + "type": "string" + }, + "next_cursor": { + "description": "Cursor for the next get_cached_result page, absent on the last page. Page reads never call the API or consume credits.", + "maxLength": 80, + "pattern": "^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}:\\d{1,16}$", + "type": "string" + }, + "offset": { + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "source_tool": { + "type": "string" + }, + "total_chars": { + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "source_tool", + "format", + "json_fragment", + "offset", + "total_chars", + "cursor", + "expires_at" + ], + "type": "object" + } + }, + "type": "object" +}
- Added
bulk_parse_user_agent - Added
bulk_security_check - Added
check_security - Added
convert_timezone - Added
get_abuse_contact - Added
get_astronomy - Added
get_astronomy_time_series - Added
get_cached_result - Changed
get_my_ip2 fields changed- added
Input schema / additionalPropertiesAdded value: +false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "error": { + "additionalProperties": false, + "properties": { + "assistant_guidance": { + "type": "string" + }, + "category": { + "type": "string" + }, + "documented_status": { + "type": "boolean" + }, + "explanation_hint": { + "type": "string" + }, + "guidance": { + "type": "string" + }, + "message": { + "type": "string" + }, + "retryable": { + "type": "boolean" + }, + "source": { + "enum": [ + "mcp_server", + "ipgeolocation_api" + ], + "type": "string" + }, + "status": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "required": [ + "source", + "category", + "message", + "retryable", + "guidance", + "assistant_guidance" + ], + "type": "object" + }, + "ip": { + "type": "string" + }, + "page": { + "additionalProperties": false, + "properties": { + "cursor": { + "description": "Opaque cursor returned in page.cursor or page.next_cursor. Retrieval requires the same server process and API key and does not repeat the original lookup.", + "maxLength": 80, + "pattern": "^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}:\\d{1,16}$", + "type": "string" + }, + "expires_at": { + "description": "ISO timestamp for idle expiry. Successful page reads extend the cache TTL; eviction or process restart can also remove the result.", + "type": "string" + }, + "format": { + "const": "structuredContent_json", + "type": "string" + }, + "json_fragment": { + "description": "JSON fragment of the original structuredContent. Fragments concatenate in offset order into the complete JSON, including bulk items and errors.", + "type": "string" + }, + "next_cursor": { + "description": "Cursor for the next get_cached_result page, absent on the last page. Page reads never call the API or consume credits.", + "maxLength": 80, + "pattern": "^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}:\\d{1,16}$", + "type": "string" + }, + "offset": { + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "source_tool": { + "type": "string" + }, + "total_chars": { + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "source_tool", + "format", + "json_fragment", + "offset", + "total_chars", + "cursor", + "expires_at" + ], + "type": "object" + } + }, + "type": "object" +}
- Added
get_timezone - Added
lookup_asn - Changed
lookup_company3 fields changed- added
Input schema / additionalPropertiesAdded value: +false - changed
Input schema / properties / ip / descriptionPrevious value: -"IPv4 or IPv6 address to look up. Omit to check the caller's IP."New value: +"IPv4 or IPv6 address to look up. Omit to check the server's public egress IP." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "data": { + "additionalProperties": { + "anyOf": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + }, + { + "type": "array" + }, + { + "type": "object" + } + ] + }, + "description": "Present on success: API result after field selection, redaction, and transport limits.", + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "error": { + "additionalProperties": false, + "description": "Present on failure, with isError: true.", + "properties": { + "assistant_guidance": { + "type": "string" + }, + "category": { + "type": "string" + }, + "documented_status": { + "type": "boolean" + }, + "explanation_hint": { + "type": "string" + }, + "guidance": { + "type": "string" + }, + "message": { + "type": "string" + }, + "retryable": { + "type": "boolean" + }, + "source": { + "enum": [ + "mcp_server", + "ipgeolocation_api" + ], + "type": "string" + }, + "status": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "required": [ + "source", + "category", + "message", + "retryable", + "guidance", + "assistant_guidance" + ], + "type": "object" + }, + "page": { + "additionalProperties": false, + "properties": { + "cursor": { + "description": "Opaque cursor returned in page.cursor or page.next_cursor. Retrieval requires the same server process and API key and does not repeat the original lookup.", + "maxLength": 80, + "pattern": "^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}:\\d{1,16}$", + "type": "string" + }, + "expires_at": { + "description": "ISO timestamp for idle expiry. Successful page reads extend the cache TTL; eviction or process restart can also remove the result.", + "type": "string" + }, + "format": { + "const": "structuredContent_json", + "type": "string" + }, + "json_fragment": { + "description": "JSON fragment of the original structuredContent. Fragments concatenate in offset order into the complete JSON, including bulk items and errors.", + "type": "string" + }, + "next_cursor": { + "description": "Cursor for the next get_cached_result page, absent on the last page. Page reads never call the API or consume credits.", + "maxLength": 80, + "pattern": "^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}:\\d{1,16}$", + "type": "string" + }, + "offset": { + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "source_tool": { + "type": "string" + }, + "total_chars": { + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "source_tool", + "format", + "json_fragment", + "offset", + "total_chars", + "cursor", + "expires_at" + ], + "type": "object" + } + }, + "type": "object" +}
- Changed
lookup_currency3 fields changed- added
Input schema / additionalPropertiesAdded value: +false - changed
Input schema / properties / ip / descriptionPrevious value: -"IPv4 or IPv6 address whose country determines the returned currency and country metadata. Omit to use the caller's IP."New value: +"IPv4 or IPv6 address whose country determines the returned currency and country metadata. Omit to use the server's public egress IP." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "data": { + "additionalProperties": { + "anyOf": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + }, + { + "type": "array" + }, + { + "type": "object" + } + ] + }, + "description": "Present on success: API result after field selection, redaction, and transport limits.", + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "error": { + "additionalProperties": false, + "description": "Present on failure, with isError: true.", + "properties": { + "assistant_guidance": { + "type": "string" + }, + "category": { + "type": "string" + }, + "documented_status": { + "type": "boolean" + }, + "explanation_hint": { + "type": "string" + }, + "guidance": { + "type": "string" + }, + "message": { + "type": "string" + }, + "retryable": { + "type": "boolean" + }, + "source": { + "enum": [ + "mcp_server", + "ipgeolocation_api" + ], + "type": "string" + }, + "status": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "required": [ + "source", + "category", + "message", + "retryable", + "guidance", + "assistant_guidance" + ], + "type": "object" + }, + "page": { + "additionalProperties": false, + "properties": { + "cursor": { + "description": "Opaque cursor returned in page.cursor or page.next_cursor. Retrieval requires the same server process and API key and does not repeat the original lookup.", + "maxLength": 80, + "pattern": "^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}:\\d{1,16}$", + "type": "string" + }, + "expires_at": { + "description": "ISO timestamp for idle expiry. Successful page reads extend the cache TTL; eviction or process restart can also remove the result.", + "type": "string" + }, + "format": { + "const": "structuredContent_json", + "type": "string" + }, + "json_fragment": { + "description": "JSON fragment of the original structuredContent. Fragments concatenate in offset order into the complete JSON, including bulk items and errors.", + "type": "string" + }, + "next_cursor": { + "description": "Cursor for the next get_cached_result page, absent on the last page. Page reads never call the API or consume credits.", + "maxLength": 80, + "pattern": "^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}:\\d{1,16}$", + "type": "string" + }, + "offset": { + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "source_tool": { + "type": "string" + }, + "total_chars": { + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "source_tool", + "format", + "json_fragment", + "offset", + "total_chars", + "cursor", + "expires_at" + ], + "type": "object" + } + }, + "type": "object" +}
- Changed
lookup_ip4 fields changed- added
Input schema / additionalPropertiesAdded value: +false - changed
Input schema / properties / fields / descriptionPrevious value: -"Comma-separated dot-path fields to return (e.g. location.city,asn.organization). Works on all plans including free. Reduces response size and can reduce credit cost when combined with include. If a field references an include-only module (for example security.* or abuse.*), this server auto-adds the required include module."New value: +"Comma-separated dot-path fields to return (e.g. location.city,asn.organization). Works on all plans including free. Reduces response size and can reduce credit cost when combined with include. Fields under security or abuse auto-add that include module. location.accuracy_radius/confidence/locality auto-add geo_accuracy; location.dma_code auto-adds dma_code. Those optional modules require a paid plan." - changed
Input schema / properties / ip / descriptionPrevious value: -"IPv4 address, IPv6 address, or domain name to look up. Domain lookups require a paid plan. Omit to use the caller's IP."New value: +"IPv4 address, IPv6 address, or domain name to look up. Domain lookups require a paid plan. Omit to use the server's public egress IP." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "data": { + "additionalProperties": { + "anyOf": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + }, + { + "type": "array" + }, + { + "type": "object" + } + ] + }, + "description": "Present on success: API result after field selection, redaction, and transport limits.", + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "error": { + "additionalProperties": false, + "description": "Present on failure, with isError: true.", + "properties": { + "assistant_guidance": { + "type": "string" + }, + "category": { + "type": "string" + }, + "documented_status": { + "type": "boolean" + }, + "explanation_hint": { + "type": "string" + }, + "guidance": { + "type": "string" + }, + "message": { + "type": "string" + }, + "retryable": { + "type": "boolean" + }, + "source": { + "enum": [ + "mcp_server", + "ipgeolocation_api" + ], + "type": "string" + }, + "status": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "required": [ + "source", + "category", + "message", + "retryable", + "guidance", + "assistant_guidance" + ], + "type": "object" + }, + "page": { + "additionalProperties": false, + "properties": { + "cursor": { + "description": "Opaque cursor returned in page.cursor or page.next_cursor. Retrieval requires the same server process and API key and does not repeat the original lookup.", + "maxLength": 80, + "pattern": "^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}:\\d{1,16}$", + "type": "string" + }, + "expires_at": { + "description": "ISO timestamp for idle expiry. Successful page reads extend the cache TTL; eviction or process restart can also remove the result.", + "type": "string" + }, + "format": { + "const": "structuredContent_json", + "type": "string" + }, + "json_fragment": { + "description": "JSON fragment of the original structuredContent. Fragments concatenate in offset order into the complete JSON, including bulk items and errors.", + "type": "string" + }, + "next_cursor": { + "description": "Cursor for the next get_cached_result page, absent on the last page. Page reads never call the API or consume credits.", + "maxLength": 80, + "pattern": "^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}:\\d{1,16}$", + "type": "string" + }, + "offset": { + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "source_tool": { + "type": "string" + }, + "total_chars": { + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "source_tool", + "format", + "json_fragment", + "offset", + "total_chars", + "cursor", + "expires_at" + ], + "type": "object" + } + }, + "type": "object" +}
- Added
lookup_network - Added
parse_user_agent
15 tool updates
v2.0.0- Changed
bulk_lookup_ip2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Input schema / properties / force_refresh / descriptionPrevious value: -"Default false. Set true only when the user asks to bypass cached bulk geolocation data; a successful refresh makes a new upstream request and can consume credits."New value: +"Default false. When true, bypasses cached bulk geolocation data; a successful refresh makes a new upstream request and can consume credits."
- Removed
bulk_parse_user_agent - Removed
bulk_security_check - Removed
check_security - Removed
convert_timezone - Removed
get_abuse_contact - Removed
get_astronomy - Removed
get_astronomy_time_series - Removed
get_timezone - Removed
lookup_asn - Changed
lookup_company2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Input schema / properties / force_refresh / descriptionPrevious value: -"Default false. Set true only when the user asks to refresh cached ownership data; a successful refresh makes a new upstream request and can consume credits."New value: +"Default false. When true, bypasses cached ownership data; a successful refresh makes a new upstream request and can consume credits."
- Changed
lookup_currency2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Input schema / properties / force_refresh / descriptionPrevious value: -"Default false. Set true only when the user asks to refresh cached currency/country data; a successful refresh makes a new upstream request and can consume credits."New value: +"Default false. When true, bypasses cached currency/country data; a successful refresh makes a new upstream request and can consume credits."
- Changed
lookup_ip2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Input schema / properties / force_refresh / descriptionPrevious value: -"Default false. Set true only when the user asks to bypass cached lookup_ip data; a successful refresh makes a new upstream request and can consume credits."New value: +"Default false. When true, bypasses cached lookup_ip data; a successful refresh makes a new upstream request and can consume credits."
- Removed
lookup_network - Removed
parse_user_agent
2 tool updates
v1.0.16- Changed
bulk_parse_user_agent1 field changed- added
Input schema / properties / uaStrings / items / minLengthAdded value: +1
- Changed
parse_user_agent1 field changed- added
Input schema / properties / uaString / minLengthAdded value: +1
12 tool updates
v1.0.15- Changed
bulk_lookup_ip1 field changed- changed
Input schema / properties / force_refresh / descriptionPrevious value: -"Default false. Leave unset unless the user asks to refresh or rerun."New value: +"Default false. Set true only when the user asks to bypass cached bulk geolocation data; a successful refresh makes a new upstream request and can consume credits."
- Changed
bulk_parse_user_agent1 field changed- changed
Input schema / properties / force_refresh / descriptionPrevious value: -"Default false. Leave unset unless the user asks to refresh or rerun."New value: +"Default false. Set true only when the user asks to refresh cached bulk user-agent parsing data; a successful refresh makes a new upstream request and can consume credits."
- Changed
bulk_security_check1 field changed- changed
Input schema / properties / force_refresh / descriptionPrevious value: -"Default false. Leave unset unless the user asks to refresh or rerun."New value: +"Default false. Set true only when the user asks to refresh cached bulk security data; a successful refresh makes a new upstream request and can consume credits."
- Changed
check_security1 field changed- changed
Input schema / properties / force_refresh / descriptionPrevious value: -"Default false. Leave unset unless the user asks to refresh or rerun."New value: +"Default false. Set true only when the user asks to refresh cached security data; a successful refresh makes a new upstream request and can consume credits."
- Changed
get_abuse_contact3 fields changed- changed
Input schema / properties / excludes / descriptionPrevious value: -"Comma-separated fields to exclude from response (e.g. phone_numbers,address)."New value: +"Comma-separated abuse fields to exclude from response (e.g. abuse.phone_numbers,abuse.address)." - changed
Input schema / properties / fields / descriptionPrevious value: -"Comma-separated fields to return (e.g. emails,organization). Reduces response size. Works on all plans."New value: +"Comma-separated abuse fields to return (e.g. abuse.emails,abuse.organization). Reduces response size." - changed
Input schema / properties / force_refresh / descriptionPrevious value: -"Default false. Leave unset unless the user asks to refresh or rerun."New value: +"Default false. Set true only when the user asks to refresh cached abuse contact data; a successful refresh makes a new upstream request and can consume credits."
- Changed
get_astronomy_time_series1 field changed- changed
Input schema / properties / force_refresh / descriptionPrevious value: -"Default false. Leave unset unless the user asks to refresh or rerun."New value: +"Default false. Set true only when the user asks to refresh cached astronomy time-series data; a successful refresh makes a new upstream request and can consume credits."
- Changed
lookup_asn1 field changed- changed
Input schema / properties / force_refresh / descriptionPrevious value: -"Default false. Leave unset unless the user asks to refresh or rerun."New value: +"Default false. Set true only when the user asks to refresh cached ASN data; a successful refresh makes a new upstream request and can consume credits."
- Changed
lookup_company1 field changed- changed
Input schema / properties / force_refresh / descriptionPrevious value: -"Default false. Leave unset unless the user asks to refresh or rerun."New value: +"Default false. Set true only when the user asks to refresh cached ownership data; a successful refresh makes a new upstream request and can consume credits."
- Changed
lookup_currency2 fields changed- changed
Input schema / properties / force_refresh / descriptionPrevious value: -"Default false. Leave unset unless the user asks to refresh or rerun."New value: +"Default false. Set true only when the user asks to refresh cached currency/country data; a successful refresh makes a new upstream request and can consume credits." - changed
Input schema / properties / ip / descriptionPrevious value: -"IPv4 or IPv6 address to look up. Omit to check the caller's IP."New value: +"IPv4 or IPv6 address whose country determines the returned currency and country metadata. Omit to use the caller's IP."
- Changed
lookup_ip1 field changed- changed
Input schema / properties / force_refresh / descriptionPrevious value: -"Default false. Leave unset unless the user asks to refresh or rerun."New value: +"Default false. Set true only when the user asks to bypass cached lookup_ip data; a successful refresh makes a new upstream request and can consume credits."
- Changed
lookup_network1 field changed- changed
Input schema / properties / force_refresh / descriptionPrevious value: -"Default false. Leave unset unless the user asks to refresh or rerun."New value: +"Default false. Set true only when the user asks to refresh cached network data; a successful refresh makes a new upstream request and can consume credits."
- Changed
parse_user_agent1 field changed- changed
Input schema / properties / force_refresh / descriptionPrevious value: -"Default false. Leave unset unless the user asks to refresh or rerun."New value: +"Default false. Set true only when the user asks to refresh cached user-agent parsing data; a successful refresh makes a new upstream request and can consume credits."
16 tool updates
v1.0.10- First observed
bulk_lookup_ip - First observed
bulk_parse_user_agent - First observed
bulk_security_check - First observed
check_security - First observed
convert_timezone - First observed
get_abuse_contact - First observed
get_astronomy - First observed
get_astronomy_time_series - First observed
get_my_ip - First observed
get_timezone - First observed
lookup_asn - First observed
lookup_company - First observed
lookup_currency - First observed
lookup_ip - First observed
lookup_network - First observed
parse_user_agent
TDQS
Scored across 17 tools
Each dedicated tool (company, currency, network, security, abuse, ASN) overlaps in data with the unified lookup_ip, which is a genuine source of confusion, but every description explicitly states the tradeoff ("this response is limited to X; lookup_ip can return these together with..."). Bulk variants are likewise cross-referenced against bulk_lookup_ip, and the timezone/astronomy singletons vs series/conversion pairs are clearly separated.
All names follow a verb_noun shape with a consistent `bulk_` prefix for batch variants (bulk_lookup_ip, bulk_security_check, bulk_parse_user_agent). The only inconsistency is verb choice for synonymous single-domain reads — lookup_company/lookup_asn vs get_abuse_contact vs check_security — which is readable but not perfectly predictable.
17 tools is slightly above the ideal band, but each maps to a distinct upstream endpoint or a distinct batch/cache primitive, so nothing feels padded. The set stays under the 25-tool red flag and the count is driven by the API's breadth (geo, timezone, astronomy, ASN, security, UA, bulk).
The surface covers the full lifecycle: single and bulk IP lookup, per-domain read tools, security and abuse, timezone get+convert, astronomy single+range, user-agent parse+bulk, plus get_my_ip and a zero-credit get_cached_result for pagination continuity. No dead ends — oversized bulk responses have a documented retrieval path.
Maintenance
Related MCP Connectors
Official IPinfo MCP Server - IP intelligence tools for AI assistants
MCP server for OpenAI API (chat completions, image generation, embeddings) via AceDataCloud
- APIVerveOAuthcom.apiverve
380+ live data, validation and utility APIs in one MCP server: IP, DNS, email, FX, weather and more.
Related MCP Servers
- AlicenseAqualityCmaintenanceIP Geolocation MCP server using IP2Location.io API to ease the query of geolocation information.116PythonMIT
- AlicenseNot gradedqualityDmaintenanceAn MCP server that provides IP geolocation services using MaxMind's GeoIP2 databases, allowing users to retrieve geographical information for single or multiple IP addresses including country, city, coordinates, and ASN details.GPL 3.0
- AlicenseNot gradedqualityFmaintenanceMCP server for IP geolocation lookups using ipinfo.io, with single, own, and batch queries.1MIT
- AlicenseNot gradedqualityDmaintenanceMCP server providing IP address lookup capabilities. Enables AI assistants to fetch details about public IP addresses or the user's current device IP.45 npmISC