Skill: tanzhengyang/my-ip-checker-iplookup (version 1.0.2)

--- name: myipchecker-ip-info description: Query the public MyIPChecker IP information API and explain or return the geolocation and network fields it provides. Use when Codex needs to look up metadata for a specific IPv4 address, fetch the caller IP information when no `ip` query parameter is provided, troubleshoot live responses from MyIPChecker, or make a real request to the deployed endpoint from a helper script. --- # MyIPChecker IP Info Treat the deployed MyIPChecker IP information endpoint as the only source of truth for this skill. Read [references/myipchecker-api.md](references/myipchecker-api.md) before describing parameters, response fields, or observed failure behavior. Use [scripts/get_myipchecker_ip_info.sh](scripts/get_myipchecker_ip_info.sh) for live requests. The script is a pure shell helper that uses `curl` and already sends a browser-style `User-Agent`, because the deployed site blocks simple non-browser request signatures. Do not describe this API as the repo's local ping route. The public endpoint currently returns IP metadata such as country, city, coordinates, timezone, ISP, and AS information. ## Workflow 1. Decide whether the user wants a live lookup, the caller IP info, an explanation of response fields, or troubleshooting for a failed request. 2. Read `references/myipchecker-api.md` for the current contract and observed edge cases. 3. Prefer a real request through `scripts/get_myipchecker_ip_info.sh`. 4. Pass `--ip <ipv4>` when the user gives a target IP. 5. Omit `--ip` when the user wants the caller IP information from the deployed service. 6. Treat non-200 responses, empty bodies, or invalid JSON as upstream/API failures rather than successful lookups. 7. Summarize the returned fields in plain language unless the user explicitly asks for raw JSON. ## Request Rules - Use `ip` as the only supported lookup parameter. - Do not rely on `target`; observed requests with `target` fall back to caller-IP behavior. - Use a browser-style `User-Agent` for live calls. - Expect JSON on success. - Handle empty error bodies gracefully. ## Response Rules - Successful responses are plain JSON objects, not the repo's `code/message/data` wrapper. - Common fields include `ip`, `country`, `countryCode`, `region`, `city`, `zip`, `lat`, `lon`, `timezone`, `isp`, `org`, and `as`. - Some fields may be absent depending on the looked-up IP. - For invalid or unsupported inputs, the deployed API may return an HTTP error with no JSON body. ## Examples - Input: `Look up 8.8.8.8 in MyIPChecker` Output: Run `sh skill/myipchecker-ip-info/scripts/get_myipchecker_ip_info.sh --ip 8.8.8.8`, then summarize the country, city, coordinates, timezone, and network owner. - Input: `What does the deployed IP info endpoint return with no parameters?` Output: Explain that the deployed endpoint returns metadata for the caller IP when `ip` is omitted, then use the helper script without `--ip` if a live call is required. - Input: `Why did my lookup fail with a 500 response?` Output: Explain that the upstream API can fail before returning a successful lookup payload, and that the error body may be empty or may contain a separate error JSON object. ## Live Call Commands ```bash sh skill/myipchecker-ip-info/scripts/get_myipchecker_ip_info.sh sh skill/myipchecker-ip-info/scripts/get_myipchecker_ip_info.sh --ip 8.8.8.8 sh skill/myipchecker-ip-info/scripts/get_myipchecker_ip_info.sh --ip 1.1.1.1 sh skill/myipchecker-ip-info/scripts/get_myipchecker_ip_info.sh --base-url <service-base-url> --ip 103.224.172.246 ``` If a live request fails with Cloudflare 1010 or another non-JSON response, say so plainly and include the HTTP status plus any response body that is available.

path: scripts/get_myipchecker_ip_info.sh
content: #!/bin/sh

set -u

BASE_URL="https://myipchecker.ai"
IP=""
TIMEOUT_SECONDS="20"
USER_AGENT="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36"

usage() {
  cat <<'EOF'
Usage: get_myipchecker_ip_info.sh [--base-url URL] [--ip IPV4] [--timeout SECONDS] [--user-agent VALUE]
EOF
}

json_escape() {
  printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g; s/\r//g; :a;N;$!ba;s/\n/\\n/g'
}

while [ "$#" -gt 0 ]; do
  case "$1" in
    --base-url)
      if [ "$#" -lt 2 ]; then
        printf 'Missing value for %s\n' "$1" >&2
        exit 2
      fi
      BASE_URL=$2
      shift 2
      ;;
    --ip)
      if [ "$#" -lt 2 ]; then
        printf 'Missing value for %s\n' "$1" >&2
        exit 2
      fi
      IP=$2
      shift 2
      ;;
    --timeout)
      if [ "$#" -lt 2 ]; then
        printf 'Missing value for %s\n' "$1" >&2
        exit 2
      fi
      TIMEOUT_SECONDS=$2
      shift 2
      ;;
    --user-agent)
      if [ "$#" -lt 2 ]; then
        printf 'Missing value for %s\n' "$1" >&2
        exit 2
      fi
      USER_AGENT=$2
      shift 2
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      printf 'Unknown argument: %s\n' "$1" >&2
      usage >&2
      exit 2
      ;;
  esac
done

BASE_URL=${BASE_URL%/}
URL="$BASE_URL/api/ip"

BODY_FILE=$(mktemp)
STATUS_FILE=$(mktemp)
cleanup() {
  rm -f "$BODY_FILE" "$STATUS_FILE"
}
trap cleanup EXIT INT TERM

if ! command -v curl >/dev/null 2>&1; then
  printf '{\n  "transport_error": "missing_curl",\n  "reason": "curl command not found",\n  "url": "%s"\n}\n' "$(json_escape "$URL")"
  exit 1
fi

if [ -n "$IP" ]; then
  HTTP_STATUS=$(curl -sS -L -G \
    -H "Accept: application/json" \
    -H "User-Agent: $USER_AGENT" \
    --connect-timeout "$TIMEOUT_SECONDS" \
    --max-time "$TIMEOUT_SECONDS" \
    --data-urlencode "ip=$IP" \
    -o "$BODY_FILE" \
    -w "%{http_code}" \
    "$URL" 2>"$STATUS_FILE")
else
  HTTP_STATUS=$(curl -sS -L \
    -H "Accept: application/json" \
    -H "User-Agent: $USER_AGENT" \
    --connect-timeout "$TIMEOUT_SECONDS" \
    --max-time "$TIMEOUT_SECONDS" \
    -o "$BODY_FILE" \
    -w "%{http_code}" \
    "$URL" 2>"$STATUS_FILE")
fi
CURL_EXIT=$?

if [ "$CURL_EXIT" -ne 0 ]; then
  REASON=$(cat "$STATUS_FILE")
  printf '{\n  "transport_error": "request_error",\n  "reason": "%s",\n  "url": "%s"\n}\n' "$(json_escape "$REASON")" "$(json_escape "$URL")"
  exit 1
fi

BODY=$(cat "$BODY_FILE")

case "$HTTP_STATUS" in
  2??)
    if [ -z "$BODY" ]; then
      printf '{\n  "transport_error": "invalid_json",\n  "url": "%s",\n  "body": ""\n}\n' "$(json_escape "$URL")"
      exit 1
    fi
    printf '%s\n' "$BODY"
    ;;
  *)
    printf '{\n  "transport_error": "http_error",\n  "status": %s,\n  "reason": "HTTP %s",\n  "url": "%s",\n  "body": "%s"\n}\n' \
      "$HTTP_STATUS" \
      "$HTTP_STATUS" \
      "$(json_escape "$URL")" \
      "$(json_escape "$BODY")"
    exit 1
    ;;
esac


path: references/myipchecker-api.md
content: # MyIPChecker API Reference

## Endpoint

- Method: `GET`
- Base URL: `https://myipchecker.ai`
- Path: `/api/ip`
- Auth: none observed during live requests
- Content type on success: `application/json`

## Purpose

Look up geolocation and network metadata for an IPv4 address.

If no `ip` query parameter is supplied, the endpoint returns metadata for the caller IP.

## Query Parameters

- `ip`: optional IPv4 address to look up

Observed behavior:

- `GET /api/ip` returns the caller IP information.
- `GET /api/ip?ip=8.8.8.8` returns metadata for `8.8.8.8`.
- `GET /api/ip?target=8.8.8.8` did not look up `8.8.8.8`; it behaved like a no-parameter request.

Do not advertise `target` as supported.

## Successful Response Shape

The deployed API returns a plain JSON object rather than a wrapped envelope.

Observed fields include:

- `ip`
- `country`
- `countryCode`
- `region`
- `city`
- `zip`
- `lat`
- `lon`
- `timezone`
- `isp`
- `org`
- `as`

Not every field is guaranteed to appear for every IP. Treat missing keys as normal.

## Observed Examples

### Caller IP lookup

Request:

```text
GET https://myipchecker.ai/api/ip
```

Observed response on 2026-03-30:

```json
{
  "ip": "103.224.172.246",
  "country": "HK",
  "countryCode": "HK",
  "city": "Hong Kong",
  "zip": "999077",
  "lat": 22.27832,
  "lon": 114.17469,
  "timezone": "Asia/Hong_Kong",
  "isp": "BACK WAVES LIMITED - HK",
  "org": "BACK WAVES LIMITED - HK",
  "as": "AS153371 BACK WAVES LIMITED - HK"
}
```

### Specific IP lookup

Request:

```text
GET https://myipchecker.ai/api/ip?ip=8.8.8.8
```

Observed response on 2026-03-30:

```json
{
  "ip": "8.8.8.8",
  "country": "US",
  "countryCode": "US",
  "region": "California",
  "city": "Mountain View",
  "zip": "94043",
  "lat": 37.4056,
  "lon": -122.0775,
  "timezone": "America/Los_Angeles",
  "isp": "AS15169 Google LLC",
  "org": "AS15169 Google LLC",
  "as": "AS15169 Google LLC"
}
```

## Failure Behavior

Observed on 2026-03-30:

- A default Python `urllib` request without a browser-style `User-Agent` was blocked by Cloudflare with HTTP `403` and error `1010`.
- `GET /api/ip?ip=exa_mple.com` returned HTTP `500`; the response body was not stable across clients and may be empty or may contain an error JSON object.

Design helpers and explanations around those facts:

- Always send a browser-like `User-Agent`.
- Distinguish HTTP or transport failures from successful lookups.
- Handle both empty and structured error bodies without crashing.


path: agents/openai.yaml
content: interface:
  display_name: "MyIPChecker IP Info"
  short_description: "Look up public MyIPChecker IP metadata"
  default_prompt: "Use this skill to make real requests to https://myipchecker.ai/api/ip, look up metadata for a specific IPv4 address with the ip query parameter, fetch caller-IP metadata when ip is omitted, and explain or troubleshoot the JSON returned by the deployed MyIPChecker API."


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (HIGH)