Skip to main content
Glama

IPInfo MCP Server

server.py14.1 kB
import os from typing import Any from fastapi import Request from fastapi.responses import JSONResponse from mcp.server.fastmcp import Context, FastMCP from .api_client import IPInfoAPIError, IPInfoClient from .api_models import ( AbuseResponse, AsnResponse, CarrierResponse, CompanyResponse, DomainsResponse, FullResponse, MeResponse, PrivacyResponse, RangesResponse, WhoisSource, ) # Create an MCP server with HTTP transport support mcp = FastMCP("IPInfo") # Global client instance for new API _client: IPInfoClient | None = None def get_client(ctx: Context[Any, Any, Any]) -> IPInfoClient: """Get or create the API client instance.""" global _client if _client is None: api_token = os.environ.get("IPINFO_API_TOKEN") if not api_token: ctx.warning("IPINFO_API_TOKEN is not set - some features may be limited") _client = IPInfoClient(api_token=api_token) return _client # Health endpoint for HTTP transport @mcp.custom_route("/health", methods=["GET"]) async def health_check(request: Request) -> JSONResponse: """Health check endpoint for monitoring.""" return JSONResponse({"status": "healthy"}) # Main IP information tool @mcp.tool() async def get_ip_info(ip: str | None, ctx: Context[Any, Any, Any]) -> FullResponse: """Get comprehensive information about an IP address. Args: ip: IP address to lookup. If None, returns info about current IP. ctx: MCP context Returns: Complete IP information including location, ASN, company, privacy, etc. """ client = get_client(ctx) try: if ip: return await client.get_info_by_ip(ip) else: return await client.get_current_info() except IPInfoAPIError as e: ctx.error(f"API error: {e.message}") raise @mcp.tool() async def get_account_info(ctx: Context[Any, Any, Any]) -> MeResponse: """Get IPInfo account information and API limits. Returns: Account information including API limits and available features. """ client = get_client(ctx) try: return await client.get_me() except IPInfoAPIError as e: ctx.error(f"API error: {e.message}") raise @mcp.tool() async def batch_lookup(ips: list[str], ctx: Context[Any, Any, Any]) -> dict[str, Any]: """Batch lookup multiple IP addresses. Args: ips: List of IP addresses to lookup (can include field paths like "8.8.8.8/city") Returns: Dictionary with IP information for each address. """ client = get_client(ctx) try: return await client.batch(ips) except IPInfoAPIError as e: ctx.error(f"API error: {e.message}") raise @mcp.tool() async def summarize_ips(ips: list[str], ctx: Context[Any, Any, Any]) -> dict[str, Any]: """Summarize a list of IP addresses with statistics and insights. Args: ips: List of IP addresses to summarize (up to 500,000) Returns: Summary report with statistics and map URL. """ client = get_client(ctx) ips_text = "\n".join(ips) try: return await client.summarize_ips(ips_text) except IPInfoAPIError as e: ctx.error(f"API error: {e.message}") raise @mcp.tool() async def map_ips(ips: list[str], ctx: Context[Any, Any, Any]) -> dict[str, Any]: """Create a visual map of IP address locations. Args: ips: List of IP addresses to map (up to 500,000) Returns: Map report with visualization URL. """ client = get_client(ctx) ips_text = "\n".join(ips) try: return await client.map_ips(ips_text) except IPInfoAPIError as e: ctx.error(f"API error: {e.message}") raise # ASN tools @mcp.tool() async def get_asn_info(asn: int, ctx: Context[Any, Any, Any]) -> AsnResponse: """Get information about an Autonomous System Number (ASN). Args: asn: The ASN number (without 'AS' prefix) Returns: ASN information including prefixes, peers, and network details. """ client = get_client(ctx) try: return await client.get_asn(asn) except IPInfoAPIError as e: ctx.error(f"API error: {e.message}") raise # Company tools @mcp.tool() async def get_company_info(ip: str, ctx: Context[Any, Any, Any]) -> CompanyResponse: """Get company information for an IP address. Args: ip: IP address to lookup Returns: Company name, domain, and type. """ client = get_client(ctx) try: return await client.get_company(ip) except IPInfoAPIError as e: ctx.error(f"API error: {e.message}") raise # Carrier tools @mcp.tool() async def get_carrier_info(ip: str, ctx: Context[Any, Any, Any]) -> CarrierResponse: """Get mobile carrier information for an IP address. Args: ip: IP address to lookup Returns: Mobile carrier details including MCC and MNC codes. """ client = get_client(ctx) try: return await client.get_carrier(ip) except IPInfoAPIError as e: ctx.error(f"API error: {e.message}") raise # Privacy detection tools @mcp.tool() async def get_privacy_info(ip: str, ctx: Context[Any, Any, Any]) -> PrivacyResponse: """Detect privacy services (VPN, proxy, Tor, etc.) for an IP address. Args: ip: IP address to check Returns: Privacy detection results including VPN, proxy, Tor, relay, and hosting status. """ client = get_client(ctx) try: return await client.get_privacy(ip) except IPInfoAPIError as e: ctx.error(f"API error: {e.message}") raise # Domains tools @mcp.tool() async def get_hosted_domains( ip: str, ctx: Context[Any, Any, Any], page: int | None = None, limit: int | None = None ) -> DomainsResponse: """Get domains hosted on an IP address. Args: ip: IP address to lookup page: Page number (starts at 0) limit: Number of results per page (max 1000, default 100) Returns: List of domains hosted on the IP address. """ client = get_client(ctx) try: return await client.get_domains(ip, page, limit) except IPInfoAPIError as e: ctx.error(f"API error: {e.message}") raise # Ranges tools @mcp.tool() async def get_ip_ranges(domain: str, ctx: Context[Any, Any, Any]) -> RangesResponse: """Get IP ranges owned by a domain/organization. Args: domain: Domain name to lookup Returns: IP ranges information including IPv4 and IPv6 blocks. """ client = get_client(ctx) try: return await client.get_ranges(domain) except IPInfoAPIError as e: ctx.error(f"API error: {e.message}") raise # Abuse tools @mcp.tool() async def get_abuse_contact(ip: str, ctx: Context[Any, Any, Any]) -> AbuseResponse: """Get abuse contact information for an IP address. Args: ip: IP address to lookup Returns: Abuse contact details including email, phone, and address. """ client = get_client(ctx) try: return await client.get_abuse(ip) except IPInfoAPIError as e: ctx.error(f"API error: {e.message}") raise # WHOIS tools @mcp.tool() async def whois_lookup_by_ip( ip: str, ctx: Context[Any, Any, Any], page: int | None = None, source: str | None = None ) -> dict[str, Any]: """WHOIS lookup by IP address or IP range. Args: ip: IP address or range to lookup page: Page number for paginated results source: Filter by WHOIS source (arin, ripe, afrinic, apnic, lacnic) Returns: WHOIS records for the IP or range. """ client = get_client(ctx) whois_source = WhoisSource(source) if source else None try: result = await client.get_whois_net_by_ip(ip, page, whois_source) return result.model_dump(exclude_none=True) except IPInfoAPIError as e: ctx.error(f"API error: {e.message}") raise @mcp.tool() async def whois_lookup_by_domain( domain: str, ctx: Context[Any, Any, Any], page: int | None = None, source: str | None = None ) -> dict[str, Any]: """WHOIS lookup by organization domain. Args: domain: Domain name to lookup page: Page number for paginated results source: Filter by WHOIS source (arin, ripe, afrinic, apnic, lacnic) Returns: WHOIS records for the domain. """ client = get_client(ctx) whois_source = WhoisSource(source) if source else None try: result = await client.get_whois_net_by_domain(domain, page, whois_source) return result.model_dump(exclude_none=True) except IPInfoAPIError as e: ctx.error(f"API error: {e.message}") raise @mcp.tool() async def whois_lookup_by_asn( asn: int, ctx: Context[Any, Any, Any], page: int | None = None, source: str | None = None ) -> dict[str, Any]: """WHOIS lookup by ASN. Args: asn: ASN number to lookup page: Page number for paginated results source: Filter by WHOIS source (arin, ripe, afrinic, apnic, lacnic) Returns: WHOIS records for the ASN. """ client = get_client(ctx) whois_source = WhoisSource(source) if source else None try: result = await client.get_whois_net_by_asn(asn, page, whois_source) return result.model_dump(exclude_none=True) except IPInfoAPIError as e: ctx.error(f"API error: {e.message}") raise # Single field tools @mcp.tool() async def get_ip_city(ctx: Context[Any, Any, Any], ip: str | None = None) -> str: """Get just the city for an IP address. Args: ip: IP address to lookup. If None, returns current city. Returns: City name. """ client = get_client(ctx) try: if ip: return await client.get_city_by_ip(ip) else: return await client.get_current_city() except IPInfoAPIError as e: ctx.error(f"API error: {e.message}") raise @mcp.tool() async def get_ip_country(ctx: Context[Any, Any, Any], ip: str | None = None) -> str: """Get just the country code for an IP address. Args: ip: IP address to lookup. If None, returns current country. Returns: Two-letter country code (ISO-3166). """ client = get_client(ctx) try: if ip: return await client.get_country_by_ip(ip) else: return await client.get_current_country() except IPInfoAPIError as e: ctx.error(f"API error: {e.message}") raise @mcp.tool() async def get_ip_region(ctx: Context[Any, Any, Any], ip: str | None = None) -> str: """Get just the region/state for an IP address. Args: ip: IP address to lookup. If None, returns current region. Returns: Region or state name. """ client = get_client(ctx) try: if ip: return await client.get_region_by_ip(ip) else: return await client.get_current_region() except IPInfoAPIError as e: ctx.error(f"API error: {e.message}") raise @mcp.tool() async def get_ip_location(ctx: Context[Any, Any, Any], ip: str | None = None) -> str: """Get just the coordinates for an IP address. Args: ip: IP address to lookup. If None, returns current location. Returns: Latitude,longitude coordinates. """ client = get_client(ctx) try: if ip: return await client.get_location_by_ip(ip) else: return await client.get_current_location() except IPInfoAPIError as e: ctx.error(f"API error: {e.message}") raise @mcp.tool() async def get_ip_postal(ctx: Context[Any, Any, Any], ip: str | None = None) -> str: """Get just the postal code for an IP address. Args: ip: IP address to lookup. If None, returns current postal code. Returns: Postal or ZIP code. """ client = get_client(ctx) try: if ip: return await client.get_postal_by_ip(ip) else: return await client.get_current_postal() except IPInfoAPIError as e: ctx.error(f"API error: {e.message}") raise @mcp.tool() async def get_ip_timezone(ctx: Context[Any, Any, Any], ip: str | None = None) -> str: """Get just the timezone for an IP address. Args: ip: IP address to lookup. If None, returns current timezone. Returns: IANA timezone string. """ client = get_client(ctx) try: if ip: return await client.get_timezone_by_ip(ip) else: return await client.get_current_timezone() except IPInfoAPIError as e: ctx.error(f"API error: {e.message}") raise @mcp.tool() async def get_ip_hostname(ctx: Context[Any, Any, Any], ip: str | None = None) -> str: """Get just the hostname for an IP address. Args: ip: IP address to lookup. If None, returns current hostname. Returns: Hostname. """ client = get_client(ctx) try: if ip: return await client.get_hostname_by_ip(ip) else: return await client.get_current_hostname() except IPInfoAPIError as e: ctx.error(f"API error: {e.message}") raise @mcp.tool() async def get_ip_org(ctx: Context[Any, Any, Any], ip: str | None = None) -> str: """Get just the organization/ASN for an IP address. Args: ip: IP address to lookup. If None, returns current organization. Returns: ASN and organization name. """ client = get_client(ctx) try: if ip: return await client.get_org_by_ip(ip) else: return await client.get_current_org() except IPInfoAPIError as e: ctx.error(f"API error: {e.message}") raise def main() -> None: """Main entry point for MCP server.""" mcp.run() if __name__ == "__main__": main()

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/NimbleBrainInc/mcp-ipinfo'

If you have feedback or need assistance with the MCP directory API, please join our Discord server