#
tokens: 2527/50000 5/5 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

```
├── .gitignore
├── .python-version
├── LICENSE
├── main.py
├── pyproject.toml
├── README.md
└── uv.lock
```

# Files

--------------------------------------------------------------------------------
/.python-version:
--------------------------------------------------------------------------------

```
1 | 3.13
2 | 
```

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
1 | __pycache__
2 | .venv
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
  1 | # WhereAmI MCP Server
  2 | 
  3 | ![Python](https://img.shields.io/badge/Python-3.10+-blue.svg)
  4 | ![License](https://img.shields.io/badge/License-MIT-green.svg)
  5 | ![Status](https://img.shields.io/badge/Status-Active-brightgreen.svg)
  6 | 
  7 | A lightweight mcp server that tells you exactly where you are based on your current IP, powered by [ipapi.co](https://ipapi.co/). 
  8 | 
  9 | ## Features
 10 | 
 11 | - **Dynamic Resources**: Fetch specific data (e.g., IP, country, city) via `location://{type}`.
 12 | - **Detailed Tool**: Generate a comprehensive location report with `get_location()`.
 13 | - **Natural Language Prompt**: Ask "Where am I?" to get detailed results.
 14 | - **Robust Error Handling**: Gracefully manages API and network issues.
 15 | - **Minimal Dependencies**: Requires only `mcp` and `httpx`.
 16 | 
 17 | ## Installation
 18 | 
 19 | ### Prerequisites
 20 | - Python 3.10+
 21 | - `pip`
 22 | 
 23 | ### Setup
 24 | 1. Clone the repository:
 25 |    ```bash
 26 |    git clone https://github.com/kukapay/whereami-mcp.git
 27 |    cd whereami-mcp
 28 |    ```
 29 | 2. Install dependencies:
 30 |    ```bash
 31 |    pip install mcp httpx
 32 |    ```
 33 | 3. (Optional) Install as an MCP service:
 34 |    ```bash
 35 |    mcp install whereami_mcp.py --name "WhereAmI"
 36 |    ```
 37 | 
 38 | ## Usage
 39 | 
 40 | ### Running the Server
 41 | - Direct execution:
 42 |   ```bash
 43 |   python whereami_mcp.py
 44 |   ```
 45 | - Development mode:
 46 |   ```bash
 47 |   mcp dev whereami_mcp.py
 48 |   ```
 49 | 
 50 | ### Components
 51 | 
 52 | #### Resource: `location://{type}`
 53 | Returns a specific location detail based on `{type}`.
 54 | - **Supported Types**: `ip`, `country`, `country_code`, `region`, `city`, `latitude`, `longitude`, `timezone`, `isp`, `asn`
 55 | - **Examples**:
 56 |   - `@location://ip` → `"8.8.8.8"`
 57 |   - `@location://city` → `"Mountain View"`
 58 |   - `@location://country` → `"United States"`
 59 | 
 60 | #### Tool: `get_location()`
 61 | Generates a detailed Markdown table of geolocation data.
 62 | - **Fields**:
 63 |   - IP
 64 |   - Country
 65 |   - Country Code
 66 |   - Region
 67 |   - City
 68 |   - Latitude
 69 |   - Longitude
 70 |   - Timezone
 71 |   - ISP
 72 |   - ASN
 73 | - **Sample Output**:
 74 |   ```
 75 |   | Field          | Value             |
 76 |   |----------------|-------------------|
 77 |   | IP            | 8.8.8.8           |
 78 |   | Country       | United States     |
 79 |   | Country Code  | US                |
 80 |   | Region        | California        |
 81 |   | City          | Mountain View     |
 82 |   | Latitude      | 37.4223           |
 83 |   | Longitude     | -122.0848         |
 84 |   | Timezone      | America/Los_Angeles |
 85 |   | ISP           | GOOGLE            |
 86 |   | ASN           | AS15169           |
 87 |   ```
 88 | 
 89 | #### Prompt: `where_am_i_prompt`
 90 | Predefined query: "Please tell me where I am based on my current IP address." Triggers `get_location()`.
 91 | 
 92 | ### Examples in Claude Desktop
 93 | 1. Install the server:
 94 |    ```bash
 95 |    mcp install whereami_mcp.py --name "WhereAmI"
 96 |    ```
 97 | 2. Query data:
 98 |    - "My IP is `@location://ip`"
 99 |    - "I’m in `@location://city`, `@location://country`"
100 | 3. Get full report:
101 |    - "Where am I?"
102 |    - `get_location()`
103 | 
104 | ## License
105 | 
106 | MIT License. See [LICENSE](LICENSE) for details.
107 | 
108 | 
```

--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------

```toml
 1 | [project]
 2 | name = "whereami-mcp"
 3 | version = "0.1.0"
 4 | description = "A lightweight mcp server that tells you exactly where you are."
 5 | readme = "README.md"
 6 | requires-python = ">=3.13"
 7 | dependencies = [
 8 |     "httpx>=0.28.1",
 9 |     "mcp[cli]>=1.4.1",
10 | ]
11 | 
```

--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------

```python
  1 | # whereami_mcp.py
  2 | import httpx
  3 | from mcp.server.fastmcp import FastMCP, Context
  4 | 
  5 | # Initialize the MCP server
  6 | mcp = FastMCP("WhereAmI", dependencies=["httpx"])
  7 | 
  8 | # API endpoint from ipapi.co
  9 | API_URL = "https://ipapi.co/json/"
 10 | 
 11 | # Mapping of type to API field names
 12 | LOCATION_FIELDS = {
 13 |     "ip": "ip",
 14 |     "country": "country_name",
 15 |     "country_code": "country_code",
 16 |     "region": "region",
 17 |     "city": "city",
 18 |     "latitude": "latitude",
 19 |     "longitude": "longitude",
 20 |     "timezone": "timezone",
 21 |     "isp": "org",
 22 |     "asn": "asn"
 23 | }
 24 | 
 25 | @mcp.resource("location://{type}")
 26 | def get_location_data(type: str) -> str:
 27 |     """
 28 |     Get specific location data based on the type parameter.
 29 |     Supported types: ip, country, country_code, region, city, latitude, longitude, timezone, isp, asn
 30 |     """
 31 |     if type not in LOCATION_FIELDS:
 32 |         return f"Error: Invalid type '{type}'. Supported types: {', '.join(LOCATION_FIELDS.keys())}"
 33 |     
 34 |     try:
 35 |         response = httpx.get(API_URL)
 36 |         response.raise_for_status()
 37 |         data = response.json()
 38 |         field = LOCATION_FIELDS[type]
 39 |         return str(data[field])
 40 |     except httpx.HTTPError as e:
 41 |         return f"Error fetching location data: {str(e)}"
 42 |     except KeyError:
 43 |         return f"Error: Field '{field}' not found in API response"
 44 | 
 45 | @mcp.tool()
 46 | def get_location(ctx: Context) -> str:
 47 |     """
 48 |     Get detailed location information based on current IP.
 49 |     
 50 |     Returns a Markdown table containing:
 51 |     - IP: The current public IP address
 52 |     - Country: Full country name
 53 |     - Country Code: Two-letter country code (ISO 3166-1 alpha-2)
 54 |     - Region: State or region name
 55 |     - City: City name
 56 |     - Latitude: Geographic latitude coordinate
 57 |     - Longitude: Geographic longitude coordinate
 58 |     - Timezone: IANA timezone identifier
 59 |     - ISP: Internet Service Provider name
 60 |     - ASN: Autonomous System Number
 61 |     """
 62 |     try:
 63 |         # Make API request
 64 |         response = httpx.get(API_URL)
 65 |         response.raise_for_status()
 66 |         data = response.json()
 67 |         
 68 |         # Construct Markdown table
 69 |         table = [
 70 |             "| Field          | Value             |",
 71 |             "|----------------|-------------------|",
 72 |             f"| IP            | {data['ip']}      |",
 73 |             f"| Country       | {data['country_name']} |",
 74 |             f"| Country Code  | {data['country_code']} |",
 75 |             f"| Region        | {data['region']}   |",
 76 |             f"| City          | {data['city']}     |",
 77 |             f"| Latitude      | {data['latitude']} |",
 78 |             f"| Longitude     | {data['longitude']}|",
 79 |             f"| Timezone      | {data['timezone']} |",
 80 |             f"| ISP           | {data['org']}      |",
 81 |             f"| ASN           | {data['asn']}      |"
 82 |         ]
 83 |         
 84 |         markdown_table = "\n".join(table)
 85 |         
 86 |         ctx.info(f"Successfully retrieved location for IP: {data['ip']}")
 87 |         return markdown_table
 88 |     
 89 |     except httpx.HTTPError as e:
 90 |         ctx.error(f"Failed to fetch location data: {str(e)}")
 91 |         return f"Error: HTTP error occurred - {str(e)}"
 92 |     except Exception as e:
 93 |         ctx.error(f"Unexpected error: {str(e)}")
 94 |         return f"Error: Unexpected error occurred - {str(e)}"
 95 | 
 96 | @mcp.prompt()
 97 | def where_am_i_prompt() -> str:
 98 |     """Prompt template for asking about current location"""
 99 |     return "Please tell me where I am based on my current IP address."
100 | 
101 | if __name__ == "__main__":
102 |     mcp.run()
```