# 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 | 
4 | 
5 | 
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()
```