BGP Explorer MCP Tools - Post-Fix Audit Report

27 live tests · 23 MCP tools · 6 fixes applied · Generated 2026-02-06 · Branch: fix/mcp-tool-audit-issues

Executive Summary

27/27
Live Tests Passed
408
Unit Tests Pass
0
Broken Tools (was 2)
6
Fixes Applied
+11
New Unit Tests
4.2
Avg. Score (was 3.5)

What Changed

FIXED (was CRITICAL): check_as_relationship no longer crashes — monocle bare JSON array responses are now normalized in _run_command(). Also fixes get_as_peers(0).

FIXED (was CRITICAL): get_rpki_status now correctly returns "INVALID" for mismatched origins. RIPE Stat's invalid_asn and invalid_length statuses are normalized to invalid.

FIXED (was SIGNIFICANT): ping_from_global with 8 locations now works — total probes capped to 50, preventing Globalping API 422 errors.

FIXED (was MODERATE): assess_network_resilience now detects Tier 1 / transit-free networks. AS3356 scores 9.2/10 (was 3.7/10).

FIXED (was MODERATE): get_asn_details now labels upstream ASNs as "Observed Upstream ASNs (from sampled routes)" with a note pointing to get_as_upstreams.

IMPROVED: IPv6 "no routes found" message now explains about more-specific prefixes and suggests get_asn_announcements as next step.

UNCHANGED (still good): All 16 previously passing tools continue to work. No regressions.

Fixes Applied

CRITICAL FIX Monocle bare array parsing

File: monocle.py:_run_command()

Monocle returns bare JSON arrays for some commands (e.g., as2rel ASN1 ASN2). Callers use .get("results", []) which crashed with AttributeError. Now normalizes lists to {"results": [...]}.

Tests added: 3 (bare array, empty array, check_relationship with empty array)

CRITICAL FIX RPKI invalid status normalization

File: ripe_stat.py:get_rpki_validation()

RIPE Stat returns "invalid_asn" or "invalid_length" but the MCP server only mapped "invalid". Variants fell through to "UNKNOWN". Now uses startswith("invalid") normalization.

Tests added: 2 (invalid_asn, invalid_length)

SIGNIFICANT FIX Globalping probe cap

File: globalping.py:_parse_locations()

8 locations × 10 limit = 80 probes, exceeding Globalping API limits. Now caps total probes to 50 by scaling per-location limit.

Tests added: 2 (cap triggered, no cap when under limit)

MODERATE FIX Tier 1 resilience detection

File: resilience.py:_score_transit()

Networks with 0 upstreams but 100+ peers and 100+ downstreams are now classified as transit-free (Tier 1) and score 1.0 instead of 0.0. "Low path diversity" recommendation skipped for transit-free networks.

Tests added: 4 (Tier 1, not Tier 1, backwards compat, skip recommendation)

IMPROVED Upstream label clarity

File: mcp_server.py:get_asn_details()

Renamed "Upstream Providers" to "Observed Upstream ASNs (from sampled routes)" with note: "Use get_as_upstreams for authoritative relationship data."

Tests added: 0 (label change only)

IMPROVED IPv6 no-routes message

File: mcp_server.py:lookup_prefix()

When no routes found for IPv6, message now explains: "many networks announce more-specific prefixes (e.g., /48s) instead of the aggregate block" and suggests get_asn_announcements.

Tests added: 0 (messaging improvement)

Live Test Results (27 Tests)

All tests run against live APIs on 2026-02-06 using local source code
#ToolResultDetailLatencyStatus
1search_asnPASSFound 26 results for "Google"133msPASS
2lookup_prefix (IPv4)PASS358 routes for 8.8.8.0/24129msPASS
3lookup_prefix (IPv6)PASS0 routes — improved message with IPv6 guidance25msIMPROVED
4get_asn_announcementsPASS5617 prefixes (2461 IPv4, 3156 IPv6) for AS13335107msPASS
5get_routing_historyPASS2 origins for 8.8.8.0/24 (7 days)77msPASS
6get_bgp_path_historyPASS750 events for 8.8.8.0/24 (1 day)335msPASS
7get_rpki_status (valid)PASSstatus="valid" for 8.8.8.0/24 + AS151691594msPASS
8get_rpki_status (invalid_asn)PASSstatus="invalid" for 1.1.1.0/24 + AS15169 (normalized)155msFIXED
9analyze_as_pathPASS271 paths, 1 origin for 1.1.1.0/24112msPASS
10compare_collectorsPASS358 collectors, consistent=True1msPASS
11get_asn_detailsPASS239 observed upstream ASNs, label updated121msIMPROVED
12check_prefix_anomaliesPASSSingle origin (AS13335), no MOAS<1msPASS
13get_as_peersPASS475 peers for AS15169336msPASS
14get_as_upstreamsPASS128 upstreams for AS13335171msPASS
15get_as_downstreamsPASS6258 downstreams for AS3356137msPASS
16check_as_relationship (no match)PASSNo relationship found (no crash)15msFIXED
17get_as_connectivity_summaryPASS521 neighbors for AS15169325msPASS
18check_as_relationship (existing)PASSAS13335 → AS174: upstream14msFIXED
19ping_from_global (default)PASS2 probes from DE2238msPASS
20ping_from_global (8 locations)PASS48 probes (capped from 80)2400msFIXED
21traceroute_from_globalPASS1 probe from DE2747msPASS
22get_ixps_for_asnPASS347 IXPs for AS15169<1msPASS
23get_networks_at_ixpPASS851 networks at AMS-IX<1msPASS
24get_ixp_detailsPASSAMS-IX, 851 participants<1msPASS
25get_network_contactsPASS0 contacts for AS15169 (private)<1msPASS
26assess_network_resilience (Tier 1)PASSAS3356 score=9.2/10, tier1=True155msFIXED
27assess_network_resilience (normal)PASSAS13335 score=10.0/10, 128 upstreams75msPASS

Before/After Comparison

Original 30-test audit scores vs post-fix status
#Original TestBeforeAfterChange
5Bidirectional relationship check (check_as_relationship)BUG (1/5)PASS (5/5)FIXED
15ASN Zero / reserved (get_as_peers(0))BUG (1/5)PASS (4/5)FIXED
17Deliberate RPKI mismatch (get_rpki_status)BUG (1/5)PASS (5/5)FIXED
18Resilience: Tier 1 scoring (assess_network_resilience)WARN (3/5)PASS (5/5)FIXED
1Upstream agreement / label (get_asn_details)WARN (3/5)IMPROVED (4/5)IMPROVED
21IPv6 prefix lookup messageFAIL (1/5)IMPROVED (3/5)IMPROVED
23IPv6 anomaly check messageFAIL (1/5)IMPROVED (3/5)IMPROVED
25IXP peering decision workflowWARN (3/5)PASS (5/5)FIXED
26Global reachability (many locations)WARN* (4/5)PASS (5/5)FIXED

Score Impact

Tests improved: 9 of 30 original tests are now better

BUG → PASS: 3 tests (Tests 5, 15, 17) — all critical/significant bugs resolved

WARN → PASS: 3 tests (Tests 18, 25, 26) — resilience, peering workflow, ping locations

FAIL/WARN → IMPROVED: 3 tests (Tests 1, 21, 23) — label clarity, IPv6 messaging

Average score: 3.5/5 → 4.2/5 (+0.7)

Broken tools: 2 → 0

No regressions: All 16 previously passing tests remain passing. All 397 original unit tests still pass.

Unit Test Coverage

Total unit tests: 408 (was 397, +11 new)

All passing: 408/408

Linter: ruff check — all checks passed

Files changed: 9 (5 source, 4 test)

Lines added: 236

Lines removed: 7

Test FileNew TestsTotalFix Covered
tests/test_sources/test_monocle.py+324Fix 1: bare array, empty array, check_relationship
tests/test_sources/test_ripe_stat.py+212Fix 2: invalid_asn, invalid_length normalization
tests/test_sources/test_globalping.py+218Fix 4: probe cap triggered, no cap when under limit
tests/test_analysis/test_resilience.py+421Fix 6: Tier 1, not Tier 1, backwards compat, skip rec

Remaining Issues (Not Addressed)

From the original audit — lower priority items still open

P1 Improve error messages for invalid input

Raw HTTP errors and API URLs leak to users for malformed CIDR input (Test #11). Missing client-side validation for date ranges (Test #14). Reserved ASN/prefix ranges not recognized (Tests #6, #7). Covering prefix suggestion for /32 lookups (Test #10).

P2 Enrich path history events with peer/path context

Path events show "(from unknown)" and lack the actual path content, reducing forensic value (Tests #16, #20).

P2 New tool: compare_routing_periods

No built-in diff/comparison mode for routing changes across time windows (Test #28). Operators must manually diff two queries.

P2 Capability gaps: prefix aggregation analysis, geolocation correlation

No aggregation efficiency analysis (Test #29). No geolocation inference from latency data (Test #30). These are new-feature requests rather than bugs.


Resolved Proposals

DONE Fix check_as_relationship monocle response parsing

Commit: dfbeacf — Normalized bare JSON array in _run_command()

DONE Fix get_rpki_status to return INVALID for mismatched origins

Commit: e360103 — Added startswith("invalid") normalization in get_rpki_validation()

DONE Fix ping_from_global with many locations

Commit: 7ebfdef — Capped total probes to 50 in _parse_locations()

DONE Add Tier 1 detection to resilience scoring

Commit: c2f6aac — Heuristic: 0 upstreams + 100+ peers + 100+ downstreams = transit-free network

DONE Clarify "Upstream Providers" label in get_asn_details

Commit: f3086fa — Relabeled to "Observed Upstream ASNs (from sampled routes)"

DONE Improve IPv6 "no routes found" message

Commit: 9280e67 — Added IPv6 more-specific prefix guidance and get_asn_announcements suggestion


Git Summary

Branch: fix/mcp-tool-audit-issues (6 commits ahead of master)

Commits:

dfbeacf fix: normalize bare JSON array response from monocle _run_command

e360103 fix: normalize RPKI "invalid_asn"/"invalid_length" statuses to "invalid"

7ebfdef fix: cap total Globalping probes to 50 to avoid API 422 errors

c2f6aac fix: detect Tier 1 transit-free networks in resilience scoring

f3086fa fix: relabel "Upstream Providers" to "Observed Upstream ASNs" in get_asn_details

9280e67 fix: improve "no routes found" message for IPv6 prefix lookups

BGP Explorer MCP Tools Post-Fix Audit · 2026-02-06 · 23 tools · 27 live tests · 408 unit tests · 6 fixes · 0 regressions