---
name: ipls-ip-lookup-service
description: Use for IP geolocation, ISP/ASN, timezone and DNS record lookups, and the caller's own public IP. Triggers include "where is this IP from", "查一下 8.8.8.8 的归属地", "resolve example.com", "what is my IP", and batch queries of several IPs/domains. Prefer the MCP tools when available; fall back to curl when MCP is not configured.
---

# IP.LS — IP Lookup Service

Zero-config IP intelligence for any agent. Prefer MCP when the client supports it; every
capability below also works over plain curl (no MCP, no API key).

## When to use

- The user asks where an IP address is located, who owns it, or what ISP/ASN it belongs to.
- The user wants DNS records (A/AAAA) of a domain, or geolocation of each resolved address.
- The user wants their own public IP (or a specific protocol stack).
- Batch: several IPs / domains at once.
- Hundreds or thousands of addresses at once (a column pasted out of a log, a firewall
  dump): use `ip_summary`. It returns counts and samples rather than every row, so the
  answer fits in context — `ip_lookup` on that many rows returns data no context window
  can hold, and counting it by hand produces errors that look like real numbers.

Do not use for: PTR/hostname reverse lookups (not supported), postal codes (not in the
free DB-IP Lite dataset), or threat-intel style scoring (not supported).

## Preferred: MCP tools (server `ipls-ip-lookup-service`, https://ip.ls/mcp, Streamable HTTP)

| Tool | Input | Returns |
|---|---|---|
| `ip_lookup` | `ip`: IPv4/IPv6 or hostname, or an array for batch | ip, city, region, country, loc, org, timezone, continent (full name) (`domain` echoes the queried domain) |
| `ip_resolved` | `host`: domain or IP | all A/AAAA records (dedup, max 6), each with geolocation |
| `ip_self` | — | the caller's own public IP + protocol stack (ipv4/ipv6) |
| `headers` | — | request headers as seen by the server |
| `ua` | — | the caller's User-Agent |
| `ip_summary` | `ips`: array of IPs/hostnames, or one whitespace/comma-separated string; optional `top`, `sample`, `prefix4`, `prefix6` | distributions by country / continent / ASN / network (default /24 for IPv4, /48 for IPv6), each bucket counting occurrences and carrying a sample — built for hundreds or thousands of addresses |

Keep tool names and descriptions in sync with `src/routes/mcp.js`.

## Reading results

- Anycast IPs (8.8.8.8, 1.1.1.1): city/loc are approximate — that is the anycast node, not a server location.
- CDN/anycast domains: the returned `ip` is the nearest edge node, not the site operator.
- Dual-stack: `ip_self` reflects the current connection stack; get the other stack with `curl -4` / `curl -6`, or — when the client cannot pick a stack (browser, PowerShell, most HTTP libraries) — with the single-stack hostnames `https://4.ip.ls` / `https://6.ip.ls` (DNS picks the stack; an unreachable `6.ip.ls` means no usable IPv6).
- No `postal` field; `timezone` is empty when coordinates are unknown.
- `continent` is the full English name (e.g. "North America"), not a two-letter code — no NA-style ambiguity.
- `ip_summary` counts each occurrence, so a repeated address counts every time; samples list distinct addresses. Check the invariants rather than trusting the shape: `counted + no_data.n = addresses`, and each `by_*` dimension sums to `counted` with its unlisted remainder reported as that dimension's `tail`. Inputs that failed are in `errors`, addresses with no database record in `no_data` — nothing is dropped silently. Counts per dimension are always deterministic: the same set of inputs in any order returns the same numbers.
- `ip_summary` returns facts only — no datacenter/residential classification, no score, no verdict. Any such reading is yours to make from the ASN, not the service's to assert.
- Data source: DB-IP Lite (CC BY 4.0). No API key, no sign-up.

## Fallback: curl (no MCP needed)

```shell
curl ip.ls                        # your own public IP
curl ip.ls/8.8.8.8                # JSON geolocation
curl ip.ls/example.com            # domain lookup (adds "domain" field)
curl ip.ls/baidu.com/resolved     # all A/AAAA records
curl ip.ls/8.8.8.8/city           # single field: city / loc / org / timezone / continent
curl ip.ls/city                   # single field of your own IP
curl -4 ip.ls; curl -6 ip.ls      # force a protocol stack
curl 4.ip.ls; curl 6.ip.ls        # no stack flag? single-stack hostnames

# batch summary (POST, up to 5000 addresses / 100 hostnames)
curl -s -X POST ip.ls/summary -H 'Content-Type: application/json' \
     -d '{"ips":["8.8.8.8","1.1.1.1","example.com"],"sample":1}'
```

Note: a browser visiting `/:ip` gets a 302 to the home page; curl/API clients do not.
