PeerGlass
Uses Cloudflare's RPKI validator to verify ROA status and provides comprehensive intelligence on Cloudflare's internet resources, including IP registration, BGP routing visibility, and historical allocation data.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@PeerGlass Check the RPKI status and BGP visibility for 1.1.1.0/24"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
π PeerGlass β Internet Resource Intelligence

Protocol note: PeerGlass uses RDAP (Registration Data Access Protocol β RFC 7480β7484). RDAP (RFC 7480β7484) is the IANA-mandated JSON successor to legacy plain-text WHOIS. Where you see "historical-whois" in source code or API responses, that is RIPE Stat's own name for their endpoint β it is not our protocol choice.
Query all 5 global Regional Internet Registries simultaneously using RDAP, validate routes via RPKI, inspect BGP routing visibility, trace full historical allocation timelines, discover IXP peering data via PeeringDB, and monitor network health β all from natural language in Claude or via REST API.
What Are the 5 RIRs?
Think of the internet's IP address space like a global land registry. IANA (the root) delegates large blocks to 5 regional bodies:
RIR | Region | Countries |
π AFRINIC | Africa | 54 |
π APNIC | Asia-Pacific | 56 economies |
π ARIN | North America | USA, Canada, Caribbean |
π LACNIC | Latin America & Caribbean | 33 |
π RIPE NCC | Europe, Middle East, Central Asia | 75+ |
Related MCP server: NetworksDB-MCP
Quick Start
Install
git clone https://github.com/duksh/peerglass
cd peerglass
pip install -e .Configure MCP Clients (Claude and others)
PeerGlass runs as a standard MCP stdio server (mcp.run() in server.py),
so any MCP-compatible AI client can use it β not just Claude Desktop.
For Claude Desktop, edit
~/Library/Application Support/Claude/claude_desktop_config.json (macOS)
or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"peerglass": {
"command": "peerglass",
"args": []
}
}
}If peerglass is not in your PATH, use:
{
"mcpServers": {
"peerglass": {
"command": "python",
"args": ["/full/path/to/peerglass/server.py"]
}
}
}Restart Claude Desktop. All 42 tools become immediately available.
Start the REST API
uvicorn api:app --host 0.0.0.0 --port 8000 --reloadInteractive docs at: http://localhost:8000/docs
Start the Web UI
cd ui
npm install
npm run dev # Dev server at http://localhost:5173For production build:
cd ui
npm run build # Output in ui/dist/Set VITE_API_BASE_URL to point at your PeerGlass API deployment:
VITE_API_BASE_URL=https://api.peerglass.io npm run buildExample Queries (Natural Language in Claude)
Phase 1 β Registry lookups:
"Who owns the IP address 185.220.101.1?"
"What is the abuse contact for 8.8.8.8?"
"Who is AS13335 registered to?"
"Are all 5 RIR RDAP servers online right now?"Phase 2 β Routing security:
"Is the route 1.1.1.0/24 via AS13335 RPKI valid?"
"Is 8.8.8.0/24 currently visible in the global BGP table?"
"What prefixes is AS15169 (Google) announcing right now?"
"Find all internet resources registered to Cloudflare globally."Phase 3 β Historical intelligence:
"Show me the full registration history of 8.8.8.0/24."
"Has the prefix 192.0.2.0/24 ever been transferred between organizations?"
"Give me the global IPv4 exhaustion stats for all 5 RIRs."
"Show me the prefix hierarchy for 1.1.1.0/24 β parent blocks and sub-assignments."Phase 4 β Peering, IXPs, health & monitoring:
"Who does AS13335 (Cloudflare) peer with at internet exchanges?"
"List all IXPs where Google has a presence."
"Is the network for 1.1.1.0/24 currently healthy β any ROA issues or BGP anomalies?"
"Monitor AS13335 for changes since last baseline."Phase 5 β DNS intelligence:
"What DNS records does cloudflare.com have?"
"Is the DNSSEC chain valid for google.com?"
"Check if 1.2.3.4 is on any spam blocklist."
"Audit the email security posture of example.com."
"Has my DNS change for api.example.com propagated globally yet?"Phase 6 β TLS, certificates & threat intel:
"When does the TLS certificate for cloudflare.com expire?"
"Show me all certificates ever issued for *.example.com."
"Is 198.51.100.1 flagged as malicious β what ports and CVEs does Shodan see?"
"What hostnames has the IP 1.2.3.4 served historically?"All 42 MCP Tools
Phase 1 β Registry Queries
Tool | Description | Cache TTL |
| Query all 5 RIRs for an IP address (parallel) | 1 hour |
| Query all 5 RIRs for an ASN (parallel) | 1 hour |
| Find abuse contact for any IP globally | 1 hour |
| Health check all 5 RDAP servers | live |
| View query cache state and TTLs | live |
Phase 2 β Routing Intelligence
Tool | Description | Cache TTL |
| Validate RPKI/ROA status for prefix + ASN | 15 min |
| Check BGP visibility for a prefix or ASN | 5 min |
| List all BGP-announced prefixes for an ASN | 5 min |
| Audit all IP/ASN resources for an organization | 6 hours |
Phase 3 β Historical Intelligence
Tool | Description | Cache TTL |
| Full ownership timeline for any prefix or ASN | 12 hours |
| Detect cross-org / cross-RIR resource transfers | 12 hours |
| Global IPv4/IPv6/ASN dashboard + optional delegated IPv4 block listing ( | 24 hours |
| Prefix hierarchy: parent, children, BGP status | 1 hour |
Phase 4 β Peering, IXPs, Health & Monitoring
Tool | Description | Cache TTL |
| PeeringDB peering data + BGP neighbours for an ASN | 1 hour |
| Search Internet Exchange Points globally | 6 hours |
| RPKI + BGP + RDAP health composite check | 5 min |
| Detect changes since last baseline (delta report) | live |
Phase 5 β DNS Intelligence
Tool | Description | Cache TTL |
| DNS resolution with RDAP IP correlation (A/AAAA/PTR/MX/TXT/NSβ¦) | 5 min |
| Full DNS record enumeration β all types in one call + SPF/DMARC extraction | 5 min |
| DNSSEC chain-of-trust validation (SECURE / INSECURE / BOGUS / INDETERMINATE) | 5 min |
| DNS blocklist check against 30 RBLs in parallel (Spamhaus, Barracuda, SORBSβ¦) | 15 min |
| Email security audit: SPF, DMARC, DKIM, MX, BIMI + risk score | 15 min |
| DNS propagation check across 10 global resolvers simultaneously | live |
Phase 6 β TLS, Certificates & Threat Intelligence
Tool | Description | Cache TTL |
| TLS certificate inspection: subject, SANs, expiry, cipher suite, HSTS | 1 hour |
| Certificate Transparency log search via crt.sh β discover all certs ever issued | 6 hours |
| Threat intelligence: Shodan InternetDB (open ports, CVEs) + GreyNoise (classification, risk score) | 15 min |
| Passive DNS history via RIPE Stat β what IPs/hostnames were associated over time | 12 hours |
Phase 7 β BGP Depth
Tool | Description | Cache TTL |
| IRR route object validation via IRRExplorer β checks RIPE/RADB/ARIN/APNIC/LACNIC consistency | 1 hour |
| BGP route leak detection β identifies valley-free violations and multi-origin anomalies | 5 min |
| BGP looking glass via RIPE RIS β real AS paths from global vantage points | 5 min |
| Route flap and stability analysis β state changes, uptime %, stability score | 15 min |
Phase 8 β Humanitarian & Crisis Intelligence
Tool | Description | Cache TTL |
| Country BGP shutdown detection β compares current prefix counts vs baseline | 5 min |
| Register webhook alerts for shutdown/change events | live |
| Historical BGP shutdown timeline with SHA-256 integrity hash (for UN reports) | 1 hour |
| DNS censorship fingerprinting β detects NXDOMAIN injection, IP poisoning, DPI blocking | 10 min |
| Satellite internet tracking β Starlink, Viasat, OneWeb BGP presence | 15 min |
| Country internet chokepoint mapping β critical transit providers, resilience score | 6 hours |
| OONI censorship measurements β blocked domains, Tor accessibility, circumvention tools | 30 min |
| Composite country internet health dashboard β 0β100 score from BGP + DNS + OONI + satellite | 5 min |
Phase 9 β Advanced Platform
Tool | Description | Cache TTL |
| AS relationship classification (provider/customer/peer) via CAIDA AS-Rank API | 7 days |
| GeoIP enrichment via MaxMind GeoLite2-City (requires | 24 hours |
| RIPE Atlas distributed traceroute from global vantage points (requires | 5 min |
REST API β 41 Endpoints
PeerGlass exposes every tool as a REST endpoint, allowing integration with dashboards, scripts, and CI/CD pipelines β no Claude required.
Registry & Routing
Method | Endpoint | Description |
GET |
| RDAP lookup for an IP address |
GET |
| RDAP lookup for an ASN |
GET |
| Abuse contact for any IP |
GET |
| RPKI validation |
GET |
| BGP visibility status |
GET |
| Announced prefixes for an ASN |
GET |
| Audit all resources for an org name |
GET |
| Prefix/ASN ownership history |
GET |
| Transfer detection |
GET |
| Global IPv4/IPv6/ASN stats |
GET |
| Prefix hierarchy overview |
GET |
| Peering info from PeeringDB |
GET |
| IXP search and listing |
GET |
| Composite network health check |
GET |
| Change monitoring (delta) |
DNS Intelligence
Method | Endpoint | Description |
GET |
| DNS resolution + RDAP IP correlation |
GET |
| Full DNS record enumeration (all types) |
GET |
| DNSSEC chain-of-trust validation |
GET |
| DNS blocklist check (30 RBLs in parallel) |
GET |
| Email security audit (SPF/DMARC/DKIM/BIMI) |
GET |
| DNS propagation across 10 global resolvers |
TLS, Certificates & Threat Intel
Method | Endpoint | Description |
GET |
| TLS certificate inspection |
GET |
| Certificate Transparency log search |
GET |
| Threat intelligence (Shodan + GreyNoise) |
GET |
| Passive DNS history (RIPE Stat) |
BGP Depth
Method | Endpoint | Description |
GET |
| IRR route object validation |
GET |
| BGP route leak detection |
GET |
| BGP looking glass (RIPE RIS) |
GET |
| Route flap stability analysis |
Humanitarian & Crisis
Method | Endpoint | Description |
GET |
| Country BGP shutdown detection |
POST |
| Register shutdown webhook alert |
GET |
| Historical shutdown timeline |
GET |
| DNS censorship fingerprinting |
GET |
| Satellite connectivity status |
GET |
| Country internet chokepoints |
GET |
| OONI censorship measurements |
GET |
| Composite country internet health |
Advanced Platform
Method | Endpoint | Description |
GET |
| AS relationship classification (CAIDA) |
GET |
| GeoIP enrichment (MaxMind GeoLite2) |
GET |
| RIPE Atlas distributed traceroute |
POST |
| Bulk query up to 50 resources in one call |
Quick example:
# Look up who owns 1.1.1.1
curl http://localhost:8000/v1/ip/1.1.1.1
# Validate RPKI for Cloudflare's prefix
curl "http://localhost:8000/v1/rpki?prefix=1.1.1.0/24&asn=AS13335"
# Get BGP peers for Google
curl http://localhost:8000/v1/peering/AS15169
# List AFRINIC delegated IPv4 blocks (allocated + Ghana), paginated
curl "http://localhost:8000/v1/stats/ipv4?rir=AFRINIC&include_blocks=true&status=allocated&country=GH&limit=5&offset=0&format=json"
# DNS β enumerate all record types for a domain
curl http://localhost:8000/v1/dns/enumerate/cloudflare.com
# DNS β check email security (SPF/DMARC/DKIM)
curl http://localhost:8000/v1/dns/email/cloudflare.com
# DNS β check if an IP is on any blocklist
curl http://localhost:8000/v1/dns/dnsbl/1.2.3.4
# DNS β check propagation across 10 global resolvers
curl "http://localhost:8000/v1/dns/propagation/cloudflare.com?record_type=A"
# TLS β inspect certificate for a hostname
curl http://localhost:8000/v1/tls/cloudflare.com
# Certificates β find all certs ever issued for a domain
curl http://localhost:8000/v1/ct/cloudflare.com
# Threat intel β open ports, CVEs, risk score for an IP
curl http://localhost:8000/v1/threat/1.2.3.4
# Passive DNS β what hostnames has this IP served?
curl http://localhost:8000/v1/pdns/1.1.1.1Interactive docs (Swagger UI): http://localhost:8000/docs
Architecture
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β PEERGLASS β
β β
β Claude (LLM) REST Clients β
β β MCP / stdio β HTTP β
β βΌ βΌ β
β server.py (42 tools) api.py (41 endpoints) β
β β β β
β ββββββββββββ¬ββββββββββββββββ β
β βΌ β
β rir_client.py ββ All async HTTP calls β
β β β
β ββββββββββββΌβββββββββββββββββββ β
β βΌ βΌ βΌ β
β normalizer.py formatters.py cache.py β
β (unify RDAP) (markdown/JSON) (TTL tiers) β
β β β
β βΌ β
β models.py (Pydantic v2 data models) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
External APIs called at runtime:
βββ RDAP: rdap.afrinic.net / rdap.apnic.net / rdap.arin.net
β rdap.lacnic.net / rdap.db.ripe.net
βββ RPKI: rpki.cloudflare.com
βββ BGP: stat.ripe.net (bgp-state, announced-prefixes,
β routing-status, asn-neighbours, historical-whois)
βββ IXP: peeringdb.com/api/net, /api/ix, /api/netixlan
βββ Stats: NRO Extended Delegation Stats (all 5 RIRs)
βββ Routing: data.iana.org/rdap/ (IANA bootstrap)How Parallel Queries Work
asyncio.gather() fires all 5 RIR queries at exactly the same time:
AFRINIC ββββ responds in 1.1s ββββ 404 Not Found
APNIC ββββ responds in 0.9s ββββ β
200 OK β authoritative
ARIN ββββ responds in 1.2s ββββ 404 Not Found
LACNIC ββββ responds in 1.4s ββββ 404 Not Found
RIPE ββββ responds in 0.8s ββββ 404 Not Found
Total wall-clock time: ~1β2s (parallel) vs ~6β8s (sequential)Web UI (Sprint 7)
PeerGlass includes a search-first, dark terminal-themed web frontend built with React 18 + Vite 5 + TypeScript + Tailwind CSS.
Features
Auto-detection: Paste any IP, ASN, prefix, domain, or 2-letter country code β the UI auto-detects the type and runs the right tool
7 tool categories: Registry Β· Routing Β· DNS Β· TLS Β· Threat Β· Crisis Β· Peering
Dark terminal theme: Dark background, monospace font (JetBrains Mono), cyan/green accent palette
Markdown rendering: All API results rendered as formatted markdown with syntax highlighting
Crisis dashboard: One-click country health check for Syria, Myanmar, Ukraine, Belarus, Iran, Russia and more
41 tools accessible: Every REST endpoint is exposed via the UI
Configuration
Variable | Default | Description |
|
| PeerGlass API base URL |
Directory structure
ui/
βββ src/
β βββ App.tsx # Main layout + tab state
β βββ components/
β β βββ SearchBar.tsx # Search input with auto-type detection
β β βββ ResultPanel.tsx # Markdown result renderer
β β βββ TabBar.tsx # Category + tool tab navigation
β β βββ StatusBadge.tsx # RPKI/BGP/shutdown status indicators
β β βββ CountryDashboard.tsx # Crisis country quick-access grid
β βββ hooks/
β β βββ usePeerGlass.ts # Query state management hook
β βββ api/
β βββ client.ts # Typed wrappers for all 41 endpoints
βββ dist/ # Production build outputTesting
PeerGlass has two separate test suites serving different purposes. You should run both β they catch different categories of problems.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β TESTING PYRAMID β
β β
β πΊ INTEGRATION TESTS (test_integration.py) β
β /\ Real internet. Real APIs. Real data. β
β / \ Proves the product actually works end-to-end. β
β /ββββ\ Run this on your machine or a GCP VM. β
β β
β πΊ UNIT / STATIC TESTS (test_peerglass.py) β
β /\ In-memory. No network. Instant. β
β / \ Proves code structure, branding, and wiring. β
β /ββββ\ Runs anywhere including CI/CD. β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββTest 1 β Static / Unit Tests (test_peerglass.py)
What it checks:
# | Test | What It Verifies |
1 | Compile check | All 7 |
2 | Branding audit | No stale legacy product/server identity strings |
3 | RDAP endpoints | All 5 RIR RDAP URLs are present and correct |
4 | Protocol header |
|
5 | User-Agent | Updated to |
6 | MCP server name |
|
7 | Tool count | Exactly 42 |
8 | REST endpoints | All 41 routes present in |
9 | FastAPI runtime | TestClient hits 3 endpoints in-memory, validates responses |
10 | README | PeerGlass branding, 42 tools, RDAP note all present |
How to run:
cd peerglass
python test_peerglass.pyExpected output:
============================================================
PEERGLASS β COMPLETE TEST SUITE
============================================================
1. COMPILE CHECK
β
server.py β
rir_client.py β
formatters.py
β
models.py β
cache.py β
normalizer.py β
api.py
2. BRANDING AUDIT β no stale WHOIS identity strings
β
server.py β
rir_client.py β
README.md ...
...
β
ALL TESTS PASSED β 0 errors
Python files: 7 | MCP tools: 42 | REST endpoints: 41
Protocol: RDAP throughout (RFC 7480-7484)
Branding: PeerGlass throughout
============================================================When to run: Before every commit. Runs in under 3 seconds. No internet required.
Test 2 β Integration Tests (test_integration.py)
What it checks:
Real HTTP calls to external internet registries/data providers using well-known, stable test fixtures (Cloudflare AS13335, Google AS15169, 1.1.1.0/24). Every test asserts on actual response data β not just that the server responded.
# | Test | API Called | Fixture | Assertion |
1 | RDAP reachability | All 5 RIRs |
| HTTP 200 or 404 (both mean server is up) |
2 | RDAP IP lookup | APNIC |
|
|
3 | RDAP ASN lookup | ARIN |
|
|
4 | RPKI validation | RIPE Stat |
|
|
5 | BGP status | RIPE Stat |
| Prefix visible to RIS peers, origin ASN present |
6 | Announced prefixes | RIPE Stat |
| >= 5 prefixes, mix of IPv4 + IPv6 |
7 | Historical data | RIPE Stat |
|
|
8 | PeeringDB network | PeeringDB |
| Network record found, peering policy present |
9 | IANA Bootstrap | IANA |
| Mapped to correct RDAP service URL |
10 | AFRINIC RDAP | AFRINIC |
|
|
11 | ASN neighbours | RIPE Stat |
| Upstream / peer ASN list returned |
12 | PeeringDB IXPs | PeeringDB | global | IXP list with name and country |
13 | IANA consistency | IANA/ICANN | IPv4 + IPv6 + ASN bootstrap files | All 5 RIR service URLs present |
How to run:
# On your local machine or a GCP VM (requires internet access)
cd peerglass
python test_integration.pyExpected output (passing):
============================================================
PEERGLASS β LIVE INTEGRATION TEST SUITE
Real HTTP calls. No mocks. No fakes.
============================================================
Time: 2026-02-20 14:00:00 UTC
APIs: RIPE Β· ARIN Β· APNIC Β· LACNIC Β· AFRINIC Β· RIPE Stat Β· PeeringDB Β· IANA
ββββββββββββββββββββββββββββββββββββββββββββ
TEST 1 β RDAP Server Reachability (all 5 RIRs)
ββββββββββββββββββββββββββββββββββββββββββββ
β
PASS RIPE RDAP reachable HTTP 404
β
PASS ARIN RDAP reachable HTTP 404
β
PASS APNIC RDAP reachable HTTP 200
β
PASS LACNIC RDAP reachable HTTP 404
β
PASS AFRINIC RDAP reachable HTTP 404
...
============================================================
SUMMARY
Checks run : 48
β
Passed : 47
β Failed : 0
β οΈ Skipped : 1
Duration : ~20-40s
π ALL TESTS PASSED β PeerGlass live APIs confirmed working!
============================================================When to run:
Before a release
After any change to
rir_client.py(the HTTP layer)After any change to the external API URLs or parameters
On a schedule (e.g. daily cron on a GCP VM) to detect API changes upstream
Why this cannot run in CI/CD without configuration:
The integration tests require outbound internet access to external APIs
(RIPE, ARIN, APNIC, LACNIC, AFRINIC, RIPE Stat, PeeringDB, IANA). Standard CI runners (GitHub Actions
free tier) have internet access, so these tests can run there. Restricted
sandboxes (Anthropic Claude environment, some corporate proxies) will block
the outbound calls and every test will fail with 403 Forbidden β this is
expected behaviour of the sandbox, not a bug in PeerGlass.
Understanding Test Results
Why does RDAP return 404 and still pass?
APNIC owns 1.1.1.0/24 (Cloudflare's block). If you ask RIPE for 1.1.1.1:
You: GET https://rdap.db.ripe.net/ip/1.1.1.1
RIPE: HTTP 404
This 404 is RIPE saying "I know about this IP but it's not mine."
The server is alive and working correctly. 404 = server reachable.
200 = server reachable AND it's the authoritative RIR for that IP.
Both are valid success states for the reachability test.Why does Test 7 sometimes SKIP?
RIPE Stat's historical-whois endpoint has variable coverage. For some
ASNs it returns rich history; for others the objects array is empty.
An empty array is a valid API response β the skip is logged to distinguish
"no data" from "API broken".
Running Both Suites Together
cd peerglass
# Step 1: Always run static tests first (fast, catches code errors)
python test_peerglass.py
echo "Exit code: $?"
# Step 2: Only run integration tests if static tests pass
if [ $? -eq 0 ]; then
python test_integration.py
fiVerification β Source-Pinned Retrieval vs Model Recall
If you want to verify that PeerGlass is deterministic and source-pinned (real API retrieval) rather than model recall, run this quick check.
Ask ChatGPT to fetch all 5 RIR RDAP endpoints for
1.1.1.1and return raw JSON only.Repeat the exact same prompt multiple times.
Compare ChatGPT output against direct endpoint results below.
Use this prompt in ChatGPT:
For IP 1.1.1.1, query these exact RDAP endpoints and return ONLY JSON:
- AFRINIC: https://rdap.afrinic.net/rdap/ip/1.1.1.1
- APNIC: https://rdap.apnic.net/ip/1.1.1.1
- ARIN: https://rdap.arin.net/registry/ip/1.1.1.1
- LACNIC: https://rdap.lacnic.net/rdap/ip/1.1.1.1
- RIPE: https://rdap.db.ripe.net/ip/1.1.1.1
Output schema per RIR:
{
"rir": "...",
"url": "...",
"http_status": ...,
"objectClassName": "... or null",
"handle": "... or null",
"error": "... or null"
}
Do not summarize. Do not infer.Ground-truth script (direct endpoint calls):
python - <<'PY'
import asyncio
import json
import httpx
ENDPOINTS = {
"AFRINIC": "https://rdap.afrinic.net/rdap/ip/1.1.1.1",
"APNIC": "https://rdap.apnic.net/ip/1.1.1.1",
"ARIN": "https://rdap.arin.net/registry/ip/1.1.1.1",
"LACNIC": "https://rdap.lacnic.net/rdap/ip/1.1.1.1",
"RIPE": "https://rdap.db.ripe.net/ip/1.1.1.1",
}
async def query_one(client, rir, url):
try:
r = await client.get(url, timeout=20)
content_type = r.headers.get("content-type", "")
data = r.json() if "json" in content_type else {}
return {
"rir": rir,
"url": url,
"http_status": r.status_code,
"objectClassName": data.get("objectClassName"),
"handle": data.get("handle"),
"error": None,
}
except Exception as exc:
return {
"rir": rir,
"url": url,
"http_status": None,
"objectClassName": None,
"handle": None,
"error": str(exc),
}
async def main():
headers = {
"Accept": "application/rdap+json",
"User-Agent": "peerglass/verification",
}
async with httpx.AsyncClient(headers=headers, follow_redirects=True) as client:
results = await asyncio.gather(*[
query_one(client, rir, url) for rir, url in ENDPOINTS.items()
])
print(json.dumps(results, indent=2))
asyncio.run(main())
PYIf ChatGPT outputs are inconsistent or fail to fetch while direct calls are stable, that difference is exactly why PeerGlass uses deterministic source-pinned retrieval.
Adding Your Own Integration Tests
The test_integration.py script is designed to be extended. Each test follows
this pattern:
async def test_your_thing():
section("TEST N β Short description")
print(" What API, what fixture, what you expect")
url = "https://example-api.com/endpoint"
params = {"resource": "your-fixture", "sourceapp": "peerglass-test"}
headers = {"Accept": "application/json", "User-Agent": "peerglass/1.0.0 (integration-test)"}
try:
async with httpx.AsyncClient(timeout=25.0) as client:
resp = await client.get(url, params=params, headers=headers)
if resp.status_code != 200:
fail("API returned 200", f"HTTP {resp.status_code}"); return
data = resp.json()
value = data.get("some", {}).get("field", "")
ok("Field is what I expected", f"value='{value}'") if value == "expected" else fail("Field check", f"Got '{value}'")
except Exception:
fail("API call failed", traceback.format_exc()[-120:])Then add it to the main() coroutine:
async def main():
...
await test_your_thing() # β add here
...External APIs Used
API | Purpose | Cache TTL |
All 5 RIR RDAP endpoints | IP/ASN registration data (RDAP JSON) | 1 hr |
| Bootstrap: which RIR owns which IP/ASN range | permanent |
| RPKI/ROA validation (Validated ROA Payloads) | 15 min |
| BGP routing table visibility | 5 min |
| Prefixes announced by an ASN | 5 min |
| BGP peer/upstream/downstream ASNs | 1 hr |
| RDAP object change history (RIPE's naming) | 12 hr |
| Allocation lifecycle events | 12 hr |
| Prefix hierarchy metadata | 1 hr |
| Routing status and visibility | 5 min |
| Network peering policies | 1 hr |
| Internet Exchange Point directory | 6 hr |
| Network-to-IXP membership records | 1 hr |
NRO Extended Delegation Stats | Authoritative IPv4/IPv6/ASN allocation counts (all 5 RIRs) | 24 hr |
Phase 3 Data Sources Explained
RIPE Stat historical-whois
Records every change ever made to an RDAP object: when the org field changed,
when the status changed, when a new maintainer was added. Used by
rir_prefix_history and rir_detect_transfers. The name "historical-whois"
is RIPE Stat's own endpoint naming β PeerGlass uses RDAP protocol throughout.
Coverage: Best for RIPE NCC resources. Partial for other RIRs.
RIPE Stat allocation-history
Logs the full allocation lifecycle: when a block was first allocated from the RIR pool, when it was sub-allocated to an ISP, when it was returned.
NRO Extended Delegation Stats
Published daily by each RIR as a pipe-delimited text file. Contains every
single IP and ASN record ever created, with current status. Authoritative
source for rir_ipv4_stats.
RIPE Stat prefix-overview / less-specifics / more-specifics
Three APIs queried in parallel to build the prefix hierarchy tree for
rir_prefix_overview.
Use Case Workflows
BGP Hijack Investigation
1. rir_query_ip(suspicious_ip) β Who registered this IP?
2. rir_check_bgp_status(prefix) β Which ASN is announcing it right now?
3. rir_check_rpki(prefix, asn) β Is the announcement RPKI-valid?
4. rir_prefix_overview(prefix) β Any unexpected more-specifics?
5. rir_detect_transfers(prefix) β Did this block recently change hands?M&A Due Diligence
1. rir_audit_org(company_name) β What IP blocks does this company own?
2. rir_prefix_history(each_prefix) β When were they acquired?
3. rir_detect_transfers(each_prefix) β Were any transferred recently?
4. rir_get_announced_prefixes(asn) β What are they actively routing?Peering & IXP Analysis
1. rir_get_peering_info(asn) β Where does this network peer?
2. rir_lookup_ixps(city or ixp_name) β Find IXPs in a region
3. rir_network_health(asn) β Is the network healthy?
4. rir_change_monitor(asn) β Any changes since last check?Policy Research / ISOC Report
1. rir_ipv4_stats() β Full global IPv4/IPv6/ASN dashboard
2. rir_ipv4_stats(rir_filter="AFRINIC")β Africa-specific detail
3. Compare ipv6_total_prefixes across β IPv6 adoption rates by regionIPv4 Exhaustion Context
RIR | IPv4 Free Pool Exhausted |
APNIC | 15 April 2011 |
RIPE NCC | 14 September 2012 |
ARIN | 24 September 2015 |
LACNIC | June 2020 |
AFRINIC | 2020β2021 |
All RIRs now operate under transfer policies. IPv4 addresses trade on the
secondary market. rir_ipv4_stats tracks remaining pools in real time.
License
MIT
Available Tools
42 toolspeerglass_atlas_traceARead-only
Launch a RIPE Atlas traceroute measurement to a target IP or hostname.
Uses the RIPE Atlas global probe network (thousands of vantage points). Requires PEERGLASS_RIPE_ATLAS_KEY environment variable with a valid Atlas API key (free from atlas.ripe.net).
Args: params (AtlasTraceInput): - target (str): IP address or hostname - probes (int): Number of probes to use (default 5, max 25) - response_format (str): 'markdown' (default) or 'json'
Returns: str: Traceroute hop tables per probe with RTT and IP at each hop.
Inputs: params (required). Returns: result
peerglass_country_chokepointsARead-onlyIdempotent
Map internet resilience for a country by identifying transit providers that many in-country ASNs depend on, and computing a resilience score.
Countries with 1β2 dominant upstream providers are catastrophically vulnerable β cutting those providers isolates the entire country.
Args: params (ChokePointInput): - country_code (str): ISO 3166-1 alpha-2 code e.g. 'SY', 'BY' - response_format (str): 'markdown' (default) or 'json'
Returns: str: Resilience score (0β100), transit providers by dependency, single-upstream count.
Inputs: params (required). Returns: result
peerglass_country_healthARead-onlyIdempotent
Composite country internet health score combining: β’ BGP shutdown detection (40%) β routing table withdrawal analysis β’ DNS censorship probe (30%) β neutral vs ISP resolver comparison β’ OONI app score (20%) β blocked domains and tool access β’ Satellite availability (10%) β Starlink/Viasat/OneWeb BGP presence
Gives journalists, NGO directors, and crisis responders a single 0β100 score and plain-language summary of internet conditions.
Args: params (CountryHealthInput): - country_code (str): ISO 3166-1 alpha-2 code e.g. 'UA', 'SY', 'MM' - response_format (str): 'markdown' (default) or 'json'
Returns: str: Overall score, severity level, component scores, and plain-language summary.
Inputs: params (required). Returns: result
peerglass_ct_logsARead-onlyIdempotent
Search crt.sh for all TLS certificates ever issued for a domain via Certificate Transparency logs. Returns deduplicated entries showing common name, issuer CA, validity period, and SAN name_value.
Useful for:
Discovering shadow IT / undocumented subdomains
Auditing which CAs have been used for a domain
Finding certificates issued before/after security incidents
Verifying certificate rotation
Args: params (CTLogInput): - domain (str): Domain name (e.g. 'cloudflare.com') - limit (int): Max entries to return (default 50, max 500) - response_format (str): 'markdown' (default) or 'json'
Returns: str: Certificate log table with CN, CA, validity dates, and unique CA summary.
Inputs: params (required). Returns: result
peerglass_dns_censorshipARead-onlyIdempotent
Probe for DNS censorship by querying a domain from multiple resolver vantage points β neutral global resolvers (Cloudflare, Google, Quad9) and optionally country-specific ISP resolvers.
Detects: β’ NXDOMAIN injection β domain exists globally but ISP returns NXDOMAIN β’ IP poisoning β ISP returns a different (block-page) IP β’ DPI block β timeout / connection refused
Args: params (CensorshipProbeInput): - domain (str): Domain to probe e.g. 'twitter.com' - country_code (str, optional): ISO code for country-specific resolvers - response_format (str): 'markdown' (default) or 'json'
Returns: str: Censorship status, technique, and per-resolver response table.
Inputs: params (required). Returns: result
peerglass_dns_dnsblARead-onlyIdempotent
Check an IPv4 address against 30 DNS blocklists simultaneously, including Spamhaus ZEN, Barracuda, SORBS, URIBL, and more. All queries run in parallel for fast results.
Args: params (DNSBLInput): - ip (str): IPv4 address to check (e.g. '1.2.3.4') - response_format (str): 'markdown' (default) or 'json'
Returns: str: Per-list listed/clean status with return codes and descriptions.
Inputs: params (required). Returns: result
peerglass_dns_dnssecARead-onlyIdempotent
Validate the DNSSEC chain-of-trust for a domain. Checks DNSKEY, DS, and RRSIG records and reports SECURE / INSECURE / BOGUS / INDETERMINATE.
BOGUS status means signatures exist but fail validation β a serious indicator of misconfiguration or potential tampering.
Args: params (DNSSECInput): - domain (str): Domain name (e.g. 'cloudflare.com') - response_format (str): 'markdown' (default) or 'json'
Returns: str: DNSSEC status, chain validity, record counts, and signing algorithms.
Inputs: params (required). Returns: result
peerglass_dns_email_securityARead-onlyIdempotent
Comprehensive email security posture check for a domain:
SPF: record presence, validity, and policy strength (-all / ~all / ?all)
DMARC: policy (none/quarantine/reject), pct coverage, rua/ruf reporting
DKIM: probes common selectors (google, selector1, default, k1, mail β¦)
MX: mail server records
BIMI: brand indicator for message identification
Risk score: LOW / MEDIUM / HIGH / CRITICAL with specific issues listed
Args: params (EmailSecurityInput): - domain (str): Domain name (e.g. 'example.com') - response_format (str): 'markdown' (default) or 'json'
Returns: str: Full email security audit with risk level, score, and recommendations.
Inputs: params (required). Returns: result
peerglass_dns_enumerateARead-onlyIdempotent
Enumerate all common DNS record types for a domain in one call: A, AAAA, MX, NS, TXT, SOA, CNAME, CAA, SRV β plus extracts SPF and DMARC policies inline.
Args: params (DNSEnumerateInput): - domain (str): Domain name (e.g. 'cloudflare.com') - response_format (str): 'markdown' (default) or 'json'
Returns: str: Per-type record tables with TTL values and extracted SPF/DMARC.
Inputs: params (required). Returns: result
peerglass_dns_propagationARead-onlyIdempotent
Check whether a recent DNS change has propagated globally by querying 10 geographically distributed resolvers simultaneously: Cloudflare (1.1.1.1), Google (8.8.8.8), Quad9, OpenDNS, Comodo, Verisign, Level3, FreeDNS, CleanBrowsing, and Alternate DNS.
Compares each resolver's answer to the majority answer and reports which resolvers are stale, diverging, or failing.
Args: params (DNSPropagationInput): - domain (str): Domain name (e.g. 'cloudflare.com') - record_type (str): DNS record type to check (default: A) - response_format (str): 'markdown' (default) or 'json'
Returns: str: Per-resolver answer table with propagation status and majority answer.
Inputs: params (required). Returns: result
peerglass_dns_resolveARead-onlyIdempotent
Resolve a hostname or reverse-lookup an IP address and correlate the result with RDAP registration data (holder, country, RIR, covering prefix).
Args: params (DNSResolveInput): - target (str): Hostname or IP address (e.g. '8.8.8.8', 'cloudflare.com') - record_type (str): DNS record type β A, AAAA, PTR, MX, TXT, NS, CNAME β¦ - response_format (str): 'markdown' (default) or 'json'
Returns: str: DNS records table + RDAP owner details for each resolved IP.
Inputs: params (required). Returns: result
peerglass_geo_lookupARead-onlyIdempotent
Look up the geographic location of an IP address using MaxMind GeoLite2.
Returns city, region, country, coordinates, and timezone when available. Requires the PEERGLASS_GEOIP_DB environment variable pointing to a GeoLite2-City.mmdb file (free download from maxmind.com with account).
Args: params (GeoLookupInput): - ip (str): IPv4 or IPv6 address - response_format (str): 'markdown' (default) or 'json'
Returns: str: City, region, country, coordinates, timezone, EU membership.
Inputs: params (required). Returns: result
peerglass_monitor_registerAIdempotent
Register a country code, ASN, or prefix for shutdown monitoring with a webhook URL. When the withdrawn% exceeds the threshold, PeerGlass will POST a JSON alert to the webhook.
Args: params (MonitorRegisterInput): - resource (str): Country code, ASN, or prefix to monitor - webhook_url (str): HTTPS URL to POST alerts to - threshold_pct (float): Alert threshold in % withdrawn (default 20%) - interval_minutes (int): Polling interval (default 5 min)
Returns: str: Registration confirmation and registration count.
Inputs: params (required). Returns: result
peerglass_ooni_reportARead-onlyIdempotent
Fetch OONI (Open Observatory of Network Interference) censorship measurements for a country over the last 30 days.
Shows confirmed blocked websites, Tor accessibility, and circumvention tool status (Psiphon, OpenVPN, Signal) as measured by OONI probes running inside the country.
Args: params (OONIReportInput): - country_code (str): ISO 3166-1 alpha-2 code e.g. 'IR', 'RU' - domain (str, optional): Filter to a specific domain - response_format (str): 'markdown' (default) or 'json'
Returns: str: Blocked domains, Tor accessibility, and circumvention tool status.
Inputs: params (required). Returns: result
peerglass_passive_dnsARead-onlyIdempotent
Query RIPE Stat Passive DNS for historical DNS records associated with an IP address or domain name. Shows what hostnames pointed to an IP (or what IPs a hostname resolved to) over time, with first/last seen timestamps and observation counts.
Useful for:
Tracing infrastructure changes over time
Finding previously-used domains for an IP
Investigating historical malware C2 infrastructure
Attribution and threat hunting
Data source: RIPE NCC's Passive DNS system, which aggregates DNS queries from recursive resolvers across the network.
Args: params (PassiveDNSInput): - resource (str): IP address or domain name - limit (int): Max records (default 100, max 500) - response_format (str): 'markdown' (default) or 'json'
Returns: str: Historical DNS records table with rrtype, value, and first/last seen dates.
Inputs: params (required). Returns: result
peerglass_satellite_connectivityARead-onlyIdempotent
Check whether satellite internet providers (Starlink, Viasat, OneWeb, SES, Inmarsat, HughesNet) are actively announcing BGP prefixes.
During ground-based internet shutdowns, satellite services often remain the only available connectivity option for journalists and aid workers.
Args: params (SatelliteConnectivityInput): - country_code (str): ISO 3166-1 alpha-2 code (used for context) - response_format (str): 'markdown' (default) or 'json'
Returns: str: Per-provider active status and announced prefix count.
Inputs: params (required). Returns: result
peerglass_shutdown_detectARead-onlyIdempotent
Detect internet shutdowns at the country level by comparing current BGP prefix counts against a stored baseline.
On the first call for a country the baseline is established. Subsequent calls measure how many prefixes have been withdrawn and classify severity: β’ NORMAL < 5% withdrawn β’ DEGRADED 5β20% withdrawn β’ PARTIAL_SHUTDOWN 20β80% withdrawn β’ FULL_SHUTDOWN > 80% withdrawn
Args: params (ShutdownDetectInput): - country_code (str): ISO 3166-1 alpha-2 code e.g. 'SY', 'IR', 'MM' - response_format (str): 'markdown' (default) or 'json'
Returns: str: Severity level, withdrawn percentage, and sampled ASN prefix counts.
Inputs: params (required). Returns: result
peerglass_shutdown_timelineARead-onlyIdempotent
Retrieve a timestamped BGP withdrawal/restoration timeline for a country or ASN over a date range. Includes a SHA-256 content hash for evidence integrity verification (useful for UN reports, press, legal proceedings).
Args: params (ShutdownTimelineInput): - resource (str): Country code (e.g. 'SY') or ASN (e.g. 'AS29256') - start_date (str): ISO date e.g. '2023-10-07' - end_date (str): ISO date e.g. '2023-10-14' - response_format (str): 'markdown' (default) or 'json'
Returns: str: Timeline of BGP events, total downtime hours, and SHA-256 integrity hash.
Inputs: params (required). Returns: result
peerglass_threat_intelARead-onlyIdempotent
Passive threat intelligence for an IP address from two sources:
Shodan InternetDB (always available, no API key required):
Open ports detected via internet scanning
CVE identifiers for detected services
Reverse DNS hostnames
Shodan tags (cdn, vpn, tor-exit, etc.)
GreyNoise Community (requires GREYNOISE_API_KEY env var):
Classification: malicious / benign / unknown
RIOT flag: trusted service (Google, Amazon, etc.)
Noise flag: benign internet background scanner
Named actor or service attribution
Produces an aggregated risk score (0β100) and level (LOW / MEDIUM / HIGH / CRITICAL).
Args: params (ThreatIntelInput): - ip (str): IPv4 address (e.g. '1.2.3.4') - response_format (str): 'markdown' (default) or 'json'
Returns: str: Open ports, CVEs, GreyNoise classification, and risk assessment.
Inputs: params (required). Returns: result
peerglass_tls_inspectARead-onlyIdempotent
Connect to hostname:port over TLS and return full certificate details: subject, issuer, Subject Alternative Names (SANs), expiry date, days remaining, self-signed flag, TLS protocol version, cipher suite, chain length, and HSTS header presence.
Useful for:
Verifying certificate validity before expiry
Detecting self-signed or untrusted certificates
Checking TLS configuration (version, cipher suite)
Auditing HSTS deployment
Args: params (TLSInspectInput): - hostname (str): Target hostname (e.g. 'cloudflare.com') - port (int): TCP port β default 443 - response_format (str): 'markdown' (default) or 'json'
Returns: str: Certificate details, expiry countdown, issuer chain, and HSTS status.
Inputs: params (required). Returns: result
rir_as_relationshipsARead-onlyIdempotent
Fetch AS relationship data from CAIDA AS-Rank API.
Classifies neighbouring ASNs as: β’ Providers (upstream transit) β’ Customers (downstream networks) β’ Peers (settlement-free peering)
Unlike RIPE Stat asn-neighbours (which only gives left/right/uncertain), CAIDA AS-Rank uses a BGP-path-based inference algorithm for higher accuracy.
Args: params (ASRelationshipInput): - asn (str): ASN e.g. 'AS13335' or '13335' - response_format (str): 'markdown' (default) or 'json'
Returns: str: Classified providers, customers, and peers with relationship type.
Inputs: params (required). Returns: result
rir_audit_orgARead-onlyIdempotent
Find all IP blocks and ASNs registered to an organization across all RIRs.
Searches RDAP entity databases at AFRINIC, APNIC, ARIN, and RIPE (LACNIC does not support RDAP entity search β a limitation is noted). Aggregates results into a unified inventory.
Use cases:
M&A due diligence: What internet resources does Company X own globally?
Security research: What is the full IP footprint of an organization?
ICANN/RIR policy: Are resources distributed across multiple RIRs?
Incident response: Did this org transfer/sell IP space recently?
Tips:
Use org handles for precision (e.g. 'GOOGL-ARIN' not 'Google')
Partial name matching is supported (e.g. 'Cloudflare' finds 'Cloudflare Inc.')
Results are cached for 6 hours.
Args: params (OrgAuditInput): - org_name (str): Organization name or handle (e.g. 'Cloudflare', 'GOOGL-ARIN') - response_format (str): 'markdown' (default) or 'json'
Returns: str: Summary of all IP blocks and ASNs by RIR, with handles, names, countries, and allocation dates. JSON schema: { "org_query": str, "total_resources": int, "ip_blocks": [{"rir": str, "handle": str, "prefix_or_asn": str, "name": str, "country": str}], "asns": [...], "rirs_found_in": [str], "errors": [str] }
Inputs: params (required). Returns: result
rir_cache_statsARead-onlyIdempotent
View the current state of the in-memory TTL cache.
The cache prevents repeated queries to RIRs within short windows, respecting rate limits and reducing latency for repeated lookups.
Returns: str: JSON with cache entry counts (total, alive, expired) and the configured TTL for each query type. Schema: { "cache_stats": {"total_entries": int, "alive": int, "expired": int}, "ttl_seconds": {"ip": int, "asn": int, "org": int, "abuse": int, "bgp": int, "rpki": int} }
Inputs: no named parameters. Returns: result
rir_change_monitorARead-only
Monitor a prefix or ASN for registration and BGP routing changes between calls.
How it works:
First call: captures a baseline snapshot of RDAP + BGP state. Stores it in memory for the server's lifetime.
Subsequent calls: fetches the current state and diffs it against the baseline. Reports exactly which fields changed and from what to what.
When changes are detected: automatically updates the baseline so the next call diffs from the new state (not the original).
reset_baseline=True: discards any stored baseline and captures fresh.
Tracked fields (8 total): RDAP: Holder, RIR, Country, Allocation Status, Abuse Email BGP: Announced (bool), Origin ASN(s), Visibility %
Severity of changes: π΄ BGP Origin ASN changed β possible hijack, verify with rir_check_rpki π΄ RDAP Holder changed β possible transfer, check rir_detect_transfers π‘ BGP Announced changed β prefix appeared/disappeared from routing π‘ Country changed β registration country updated π’ Visibility % changed β normal BGP fluctuation
Baseline persists in server memory β not in a database. If the server restarts, baselines are lost and will be recreated on next call.
Args: params (ChangeMonitorInput): - resource (str): IP prefix (e.g. '8.8.8.0/24') or ASN (e.g. 'AS15169') - reset_baseline (bool): If True, discard baseline and start fresh
Returns: str: Baseline created confirmation (first call), or diff table (subsequent calls). JSON schema: { "resource": str, "status": str, (baseline_created|changes_detected|no_changes) "baseline_captured_at": str, "checked_at": str, "changes": [{"field": str, "old_value": str, "new_value": str}], "current_holder": str, "current_rir": str, "message": str }
Inputs: params (required). Returns: result
rir_check_bgp_statusARead-onlyIdempotent
Check whether a prefix or ASN is currently visible in the global BGP routing table.
Uses RIPE Stat (which aggregates data from RIPE RIS route collectors worldwide). BGP is the internet's routing protocol β the "GPS" that tells traffic how to navigate from one network to another.
For a prefix, returns:
Whether it is currently announced in BGP
Which ASN(s) are announcing it (multiple = potential hijack)
Percentage of global BGP peers that can see it (visibility)
For an ASN, returns:
Whether the ASN has any active BGP announcements
A list of all announced prefixes (use rir_get_announced_prefixes for details)
Combine with rir_check_rpki for complete routing security assessment. Results are cached for 5 minutes (BGP tables change frequently).
Args: params (BGPStatusInput): - resource (str): Prefix (e.g. '1.1.1.0/24') or ASN (e.g. 'AS15169') - response_format (str): 'markdown' (default) or 'json'
Returns: str: BGP visibility, announcing ASNs, and prefix list. JSON schema: { "resource": str, "resource_type": str, "is_announced": bool, "announcing_asns": [str], "visibility_percent": float, "announced_prefixes": [{"prefix": str, "peers_seeing": int}] }
Inputs: params (required). Returns: result
rir_check_irrARead-onlyIdempotent
Check IRRExplorer for route objects covering a prefix and verify they are consistent with the claimed origin ASN.
IRR (Internet Routing Registry) route objects tell ISPs which ASN is authorised to originate a prefix. Inconsistent or missing route objects can cause route filtering and reachability issues even when RPKI is valid.
Args: params (IRRCheckInput): - prefix (str): CIDR prefix e.g. '1.1.1.0/24' - asn (str): Expected origin ASN e.g. 'AS13335' or '13335' - response_format (str): 'markdown' (default) or 'json'
Returns: str: Route objects per IRR source, consistency status, and missing IRR coverage.
Inputs: params (required). Returns: result
rir_check_rpkiARead-onlyIdempotent
Validate a prefix + ASN pair against the global RPKI using Cloudflare's validator.
RPKI (Resource Public Key Infrastructure) is the internet's route security framework. RIRs issue Route Origin Authorizations (ROAs) β digital certificates that cryptographically prove an ASN is authorized to announce a prefix.
Validity states: β VALID β A matching ROA exists. Route is cryptographically authorized. π¨ INVALID β A ROA exists but this ASN/prefix violates it. Possible hijack. β οΈ NOT-FOUND β No ROA exists. Route is unverified (common, not inherently bad). β UNKNOWN β Could not determine validity.
Combine with rir_check_bgp_status for full routing security assessment.
Results are cached for 15 minutes (ROAs can change, but not frequently).
Args: params (RPKICheckInput): - prefix (str): CIDR prefix e.g. '1.1.1.0/24' or '2400:cb00::/32' - asn (str): Originating ASN e.g. 'AS13335' or '13335'
Returns: str: RPKI validity state, description, and list of covering ROAs. JSON schema: { "prefix": str, "asn": str, "validity": "valid"|"invalid"|"not-found"|"unknown", "covering_roas": [{"asn": int, "prefix": str, "maxLength": int}], "description": str }
Inputs: params (required). Returns: result
rir_detect_route_leakARead-onlyIdempotent
Detect potential BGP route leaks or hijacks for a prefix using RIPE Stat BGP-state data.
Checks for:
Multiple distinct origin ASNs (possible hijack β two ASNs claiming the same prefix)
AS-path loops (valley-free violations β a transit ASN re-exporting a learned route)
Args: params (RouteLeakInput): - prefix (str): CIDR prefix e.g. '1.1.1.0/24' - response_format (str): 'markdown' (default) or 'json'
Returns: str: Leak detection result with confidence, suspect ASNs, and anomalous AS paths.
Inputs: params (required). Returns: result
rir_detect_transfersARead-onlyIdempotent
Detect past ownership or cross-RIR transfers for an IP prefix or ASN.
An ownership transfer happens when a registered org (e.g. 'GOOGL-ARIN') changes to another org ('META-1-ARIN') in the registration record. A cross-RIR transfer is rarer β it means the resource physically moved between registries (e.g. from ARIN to RIPE NCC after an acquisition).
Transfer types detected: π’ Org Change β The registering organization changed πβπ Cross-RIR β The resource moved to a different RIR π Intra-RIR β Maintainer changed within the same RIR
How it works: compares consecutive historical WHOIS object versions. If 'org' or 'mnt-by' changed between versions, a transfer is flagged. If RIR-specific suffixes in the handles differ, it's cross-RIR.
Results are cached for 12 hours.
Args: params (TransferDetectInput): - resource (str): IP prefix (e.g. '8.8.8.0/24') or ASN (e.g. 'AS15169') - response_format (str): 'markdown' (default) or 'json'
Returns: str: List of detected transfers with dates, types, from/to org, and evidence. JSON schema: { "resource": str, "resource_type": str, "transfers_detected": int, "transfers": [{"transfer_date": str, "transfer_type": str, "from_org": str, "to_org": str, "from_rir": str, "to_rir": str, "evidence": str}], "current_holder": str, "first_registered": str, "sources": [str], "notes": [str] }
Inputs: params (required). Returns: result
rir_get_abuse_contactARead-onlyIdempotent
Find the abuse contact for any IP address globally using IANA bootstrap routing.
Uses IANA RDAP Bootstrap to identify the authoritative RIR first (efficient), then queries only that RIR. Falls back to querying all 5 if bootstrap fails. Extracts abuse contacts from entity roles: 'abuse', 'technical', 'noc'.
Use this tool as the first step in any network abuse reporting workflow: spam, DDoS attacks, port scanning, credential stuffing, etc.
Results are cached for 1 hour.
Args: params (AbuseContactInput): - ip_address (str): IPv4 or IPv6 address (e.g. '185.220.101.1')
Returns: str: Markdown report with abuse email(s), phone(s), network name, organization, country, and authoritative RIR. JSON schema: { "ip_address": str, "authoritative_rir": str, "abuse_email": [str], "abuse_phone": [str], "network_name": str, "org_name": str, "country": str }
Inputs: params (required). Returns: result
rir_get_announced_prefixesARead-onlyIdempotent
Retrieve all IP prefixes currently being announced by an ASN in BGP.
This shows the ASN's complete routing footprint β every IP range it is actively advertising to the global internet via BGP. Uses RIPE Stat's announced-prefixes endpoint.
Useful for:
Understanding an organization's complete IP footprint
Detecting unexpected prefix announcements (possible hijacks)
M&A due diligence on network assets
Security research and threat intelligence
min_peers_seeing filters out unstable/flapping routes that only a small number of BGP peers can see. Higher = more stable routes only.
Results are cached for 5 minutes.
Args: params (AnnouncedPrefixesInput): - asn (str): ASN to query (e.g. 'AS13335' or '15169') - min_peers_seeing (int): Minimum peer count filter (default: 5)
Returns: str: Complete list of announced prefixes with peer visibility and first/last seen timestamps. JSON schema: { "resource": str, "is_announced": bool, "announced_prefixes": [ {"prefix": str, "peers_seeing": int, "first_seen": str, "last_seen": str} ] }
Inputs: params (required). Returns: result
rir_ipv4_statsARead-onlyIdempotent
Fetch global IPv4, IPv6, and ASN allocation statistics from all 5 RIRs.
Parses the NRO Extended Delegation Stats files β the authoritative daily publication of how each RIR has distributed address space:
How many IPv4 prefixes allocated (to ISPs) vs assigned (to end users)
Remaining free IPv4 pool (where published β most RIRs are exhausted)
IPv6 prefix count and growth
Total ASNs issued
Why this matters:
IPv4 was exhausted at IANA in 2011
APNIC exhausted in 2011, RIPE in 2012, ARIN in 2015
LACNIC near exhaustion 2020, AFRINIC followed
IPv6 transition is the only long-term solution
This tool lets you track adoption and exhaustion state in real time
Results are cached for 24 hours (stats files are published once daily).
Args: params (IPv4StatsInput): - rir_filter (str, optional): Filter to one RIR ('AFRINIC', 'APNIC', 'ARIN', 'LACNIC', 'RIPE'). Leave empty for all 5. - include_blocks (bool): Include raw delegated IPv4 blocks for the selected RIR. Requires rir_filter to be set. - status_filter (str, optional): allocated | assigned | available (free is normalized). - country_filter (str, optional): 2-letter country code filter (e.g. 'GH', 'ZA'). - limit (int): Max number of block rows when include_blocks=true. - offset (int): Pagination offset for block rows. - response_format (str): 'markdown' (default) or 'json'
Returns: str: Per-RIR table of IPv4/IPv6/ASN counts with totals and exhaustion context. JSON schema: { "queried_at": str, "rirs": [{"rir": str, "region": str, "ipv4_total_prefixes": int, "ipv4_allocated": int, "ipv4_assigned": int, "ipv4_available": int, "ipv6_total_prefixes": int, "asn_total": int, "stats_date": str}], "global_ipv4_prefixes": int, "global_ipv6_prefixes": int, "global_asns": int, "ipv4_blocks": [ {"rir": str, "country": str|null, "start_ip": str, "end_ip": str, "address_count": int, "date": str|null, "status": str} ], "blocks_total": int, "blocks_returned": int, "blocks_limit": int|null, "blocks_offset": int|null, "blocks_filters": {"rir_filter": str|null, "status_filter": str|null, "country_filter": str|null} }
Inputs: params (required). Returns: result
rir_ixp_lookupARead-onlyIdempotent
Search PeeringDB for Internet Exchange Points (IXPs) by country code or name.
An IXP is a physical location where ISPs and networks directly interconnect. Without IXPs, all traffic between two ISPs would travel via paid transit providers, costing more and adding latency. IXPs are the backbone of regional internet ecosystems.
Searching by country:
Use 2-letter ISO country code: 'MU' (Mauritius), 'ZA' (South Africa), 'DE' (Germany), 'US' (United States), 'SG' (Singapore)
Searching by name:
Partial name match: 'AMS-IX', 'LINX', 'Nairobi', 'Frankfurt'
Notable IXPs worldwide:
DE-CIX Frankfurt (Germany) β Europe's busiest, 13+ Tbps
AMS-IX (Netherlands) β 10+ Tbps
LINX (UK) β London Internet Exchange
JPNAP (Japan) β Asia-Pacific hub
Nap.Africa / JINX β African exchanges
MAURITIUS-IX β your local exchange!
Results are cached for 12 hours.
Args: params (IXPLookupInput): - query (str): 2-letter country code (e.g. 'MU') or IXP name fragment - response_format (str): 'markdown' (default) or 'json'
Returns: str: Table of matching IXPs with city, country, member count, and contact. JSON schema: { "query": str, "total_found": int, "ixps": [{"name": str, "city": str, "country": str, "member_count": int, "website": str, "tech_email": str}], "errors": [str] }
Inputs: params (required). Returns: result
rir_looking_glassARead-onlyIdempotent
Show BGP routing table entries for a prefix as seen from RIPE RIS (Route Information Service) collectors around the world.
Unlike BGP visibility (which answers whether a route exists), a looking glass shows how the route is announced β the actual AS paths from different geographic vantage points.
Args: params (LookingGlassInput): - prefix (str): CIDR prefix e.g. '1.1.1.0/24' - vantage_points (int): Max entries to return (default 10, max 50) - response_format (str): 'markdown' (default) or 'json'
Returns: str: AS paths per RIPE RIS collector with region and BGP community values.
Inputs: params (required). Returns: result
rir_network_healthARead-onlyIdempotent
Run a comprehensive parallel health check on any IP address, prefix, or ASN.
Fires all checks simultaneously (parallel asyncio): RDAP β Who owns it? Which RIR? Country? Abuse contact? BGP β Is it announced? Which ASNs? What global visibility %? RPKI β Is the announcing ASN cryptographically authorized? (prefix only) PeeringDB β Peering policy? NOC email? IXP count? (ASN only)
Synthesises a health signal dashboard: β All good β registered, announced, RPKI valid β οΈ Warning β not announced, unprotected route (no ROA), missing contacts π¨ Critical β RPKI invalid (possible hijack!), multiple origin ASNs (MOAS)
This is your first-response tool for:
"Is this IP address legitimate?"
"Is this ASN healthy and reachable?"
"Is there anything suspicious about this prefix?"
NOC incident triage, security team first-response
Results are cached for 5 minutes (includes live BGP data).
Args: params (NetworkHealthInput): - resource (str): IP ('1.1.1.1'), prefix ('1.1.1.0/24'), or ASN ('AS13335') - response_format (str): 'markdown' (default) or 'json'
Returns: str: Health signal dashboard + RDAP + BGP + RPKI + PeeringDB sections. JSON schema: { "resource": str, "resource_type": str, "queried_at": str, "rdap_holder": str, "rdap_rir": str, "rdap_country": str, "bgp_announced": bool, "bgp_announcing_asns": [str], "bgp_visibility_pct": float, "rpki_validity": str, "peering_policy": str, "peering_ixp_count": int, "health_signals": [str], "errors": [str] }
Inputs: params (required). Returns: result
rir_peering_infoARead-onlyIdempotent
Fetch peering policy, IXP presence, NOC contacts, and BGP neighbours for an ASN.
Data sources (queried in parallel):
PeeringDB (www.peeringdb.com) β the internet's peering registry
RIPE Stat asn-neighbours β live BGP upstream/downstream relationships
Information returned:
Peering policy: Open / Selective / Restrictive / No Peering
IRR AS-SET (used in route filters, e.g. AS-CLOUDFLARE)
NOC email, abuse email, peering contact email
IXP presence: which exchange points, peering IPs, link speed
BGP neighbours: up to 30 adjacent ASNs in the routing table
Use cases:
"Does Cloudflare have an Open peering policy?"
"Which IXPs is AS13335 present at?"
"What is the NOC email for AS1234 to report an incident?"
"Is this ASN a residential ISP or a CDN?"
Results are cached for 6 hours.
Args: params (PeeringInfoInput): - asn (str): ASN to look up (e.g. 'AS13335', '13335', 'AS-CLOUDFLARE') - response_format (str): 'markdown' (default) or 'json'
Returns: str: Peering policy table, IXP presence table, contacts, BGP neighbours. JSON schema: { "asn": str, "network_name": str, "policy_general": str, "noc_email": str, "irr_as_set": str, "ixp_presence": [{"name": str, "city": str, "country": str, "ipaddr4": str, "ipaddr6": str, "speed": int}], "neighbour_asns": [str], "errors": [str] }
Inputs: params (required). Returns: result
rir_prefix_historyARead-onlyIdempotent
Fetch the complete registration history for an IP prefix or ASN.
Returns a chronological timeline of every change ever recorded:
Initial registration (who, when, under which RIR)
Org / maintainer changes (potential ownership transfers)
Status changes (allocated β assigned β available)
Last-changed updates
Uses RIPE Stat's historical-whois and allocation-history APIs. Coverage is best for RIPE NCC resources; partial for other RIRs.
Use cases:
"Has this IP block ever changed hands?"
"When was this ASN first registered?"
"What organization historically owned this prefix?"
Due diligence, incident response, fraud investigation
Results are cached for 12 hours (historical records are stable).
Args: params (PrefixHistoryInput): - resource (str): IP prefix (e.g. '8.8.8.0/24') or ASN (e.g. 'AS15169') - response_format (str): 'markdown' (default) or 'json'
Returns: str: Chronological event timeline with dates, event types, and attribute changes. JSON schema: { "resource": str, "resource_type": str, "current_holder": str, "current_rir": str, "registration_date": str, "total_events": int, "events": [{"event_date": str, "event_type": str, "attribute": str, "old_value": str, "new_value": str}], "sources": [str], "errors": [str] }
Inputs: params (required). Returns: result
rir_prefix_overviewARead-onlyIdempotent
Fetch a rich hierarchical overview of an IP prefix.
IP address space is organized in a tree structure:
A /8 contains 256 /16s, each /16 contains 256 /24s, and so on.
'Less-specific' = the parent block this prefix was carved from.
'More-specific' = smaller blocks assigned within this prefix.
Think of it like a real estate map: Less-specific = the city block (containing your property) The prefix itself = your land parcel More-specific = subdivisions within your parcel
This tool fetches all three layers in parallel (3 RIPE Stat API calls simultaneously) and returns a unified view including:
Current holder and announcement status
Which ASN(s) are announcing it (multiple = potential hijack)
All less-specific (parent) prefixes up the tree
All more-specific (child) prefixes within the block
Combine with rir_check_rpki to validate the announcing ASN. Results are cached for 1 hour.
Args: params (PrefixOverviewInput): - prefix (str): IP prefix in CIDR notation (e.g. '1.1.1.0/24') - response_format (str): 'markdown' (default) or 'json'
Returns: str: Holder info, BGP status, and full prefix hierarchy table. JSON schema: { "prefix": str, "holder": str, "rir": str, "country": str, "announced": bool, "announcing_asns": [str], "allocation_status": str, "related_prefixes": [{"prefix": str, "relationship": str, "holder": str, "origin_asn": str}], "errors": [str] }
Inputs: params (required). Returns: result
rir_query_asnARead-onlyIdempotent
Query all 5 global RIRs simultaneously for an Autonomous System Number.
An ASN is a unique number assigned to a network operator (ISP, CDN, large enterprise) that participates in BGP routing. Examples: AS15169 = Google, AS13335 = Cloudflare, AS36864 = AFRINIC itself.
Accepts: 'AS15169', '15169', or named sets like 'AS-GOOGLE'. Results are cached for 1 hour.
Args: params (ASNQueryInput): - asn (str): ASN in any format (e.g. 'AS15169', '13335', 'AS-CLOUDFLARE') - response_format (str): 'markdown' (default) or 'json'
Returns: str: ASN registration details including owner, country, allocation date, abuse email, and responses from all 5 RIRs. JSON schema: { "asn": str, "results": [{"rir": str, "status": str}], "normalized": [{"rir": str, "asn": str, "name": str, "org_name": str, "country": str, "abuse_email": str}] }
Inputs: params (required). Returns: result
rir_query_ipARead-onlyIdempotent
Query all 5 global RIRs simultaneously for an IP address using RDAP.
Fires parallel RDAP requests to AFRINIC, APNIC, ARIN, LACNIC, and RIPE NCC. Exactly one RIR will be authoritative; the others return 'not found'. Normalizes all responses into a unified schema and returns a clear summary.
Results are cached for 1 hour to respect RIR rate limits.
Args: params (IPQueryInput): - ip_address (str): IPv4 or IPv6 address e.g. '1.1.1.1', '2001:4860:4860::8888' - response_format (str): 'markdown' (default) or 'json'
Returns: str: Registration details including prefix, owner, country, allocation date, abuse email, and responses from all 5 RIRs. JSON schema: { "ip": str, "results": [{"rir": str, "status": str, "error": str|null}], "normalized": [{"rir": str, "prefix": str, "name": str, "org_name": str, "country": str, "allocation_date": str, "abuse_email": str}] }
Inputs: params (required). Returns: result
rir_route_stabilityARead-onlyIdempotent
Analyse BGP route stability for a prefix over a configurable time window using RIPE Stat routing-history data.
A stable route has no state changes (no withdrawal/re-announcement cycles). Repeated flapping can indicate hardware failure, misconfiguration, or DDoS and causes router CPU load and convergence delays for peers.
Args: params (RouteStabilityInput): - prefix (str): CIDR prefix e.g. '1.1.1.0/24' - hours (int): Analysis window in hours (default 24, max 168 = 7 days) - response_format (str): 'markdown' (default) or 'json'
Returns: str: Stability score (0β100), state change count, uptime %, and event timeline.
Inputs: params (required). Returns: result
rir_server_statusARead-only
Check the real-time health of all 5 RIR RDAP servers simultaneously.
Queries the /help endpoint of each RIR (lightweight, no IP/ASN needed). Returns RDAP conformance levels and availability status.
Use this before bulk queries to verify connectivity, or to diagnose why a specific RIR's responses are failing.
Returns: str: Markdown table with RIR name, region, status (Online/Unreachable), and supported RDAP conformance extensions.
Inputs: no named parameters. Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelogβ¦
TDQS
Scored across 42 tools
Most tools have distinct purposes, with clear separation between categories like DNS, RIR queries, and internet health monitoring. However, some overlap exists within categories, such as multiple DNS tools that could be confused (e.g., dns_resolve vs dns_enumerate vs dns_propagation), and RIR tools like query_ip and query_asn that might be ambiguous without careful reading of descriptions.
All tool names follow a consistent snake_case pattern with a clear prefix structure: 'peerglass_' for internet health tools and 'rir_' for RIR-related tools. This predictable naming convention makes it easy to understand the tool's domain and purpose at a glance, with no deviations or mixed styles.
With 42 tools, the count is excessive for a single server, making it overwhelming and difficult for an agent to navigate efficiently. While the domain (internet infrastructure and health monitoring) is broad, the tool set feels bloated and could benefit from consolidation or splitting into multiple focused servers to improve usability.
The tool set provides comprehensive coverage for internet infrastructure analysis, including DNS, BGP, RIR data, threat intelligence, and censorship detection. It supports full CRUD-like operations where applicable (e.g., monitoring registration and detection) and leaves no obvious gaps, enabling agents to perform end-to-end analyses without dead ends.
Maintenance
Related MCP Connectors
Live BGP routing table and registry lookups: IP origin, ASN prefixes, transit, org search.
IP intelligence, network diagnostics, and AI service availability tools for AI agents.
IP geolocation, ASN and network data, plus VPN, proxy and Tor detection. ASN tools need no key.
Free, no-API-key network lookups for AI agents β IP geolocation, DNS, WHOIS, HTTP and SSL/TLS certificate checks, and full domain health reports.
Related MCP Servers
- AlicenseAqualityDmaintenanceEnables network information lookup through WHOIS and RIPE Database queries. Supports domain/IP/ASN lookups, AS-SET expansion, route validation, and contact information retrieval across multiple Regional Internet Registries.144MIT
- FlicenseNot gradedqualityDmaintenanceEnables natural language queries for network intelligence, IP geolocation, organization details, and DNS information via the NetworksDB API.16-
- AlicenseNot gradedqualityCmaintenanceProvides IP, ASN, and BGP routing data from RIPE Stat API, enabling whois lookups, network info, AS overview, BGP state, abuse contacts, and geolocation queries.300 npmMIT

bgphorizon-mcpofficial
AlicenseAqualityBmaintenanceEnables AI assistants to query global BGP routing intelligence, including network investigation, origin history, reachability, and health checks, with 15 tools plus resources and prompts for incident triage and reporting.18MIT