npm package: @shyzus/mcp-geocrafter
Description: GeoCrafter - MCP server for geocoding, reverse geocoding, geohash and distance calculation - Powered by Photon API
Author: Rankorr
Latest version: 1.5.5

# 🗺️ GeoCrafter - Multi-Provider Geocoding MCP Server

GeoCrafter is a clean, modular MCP server for geocoding and reverse geocoding with **multi-provider support** — Google Geocoding API and Photon API (OpenStreetMap). The LLM intelligently picks the best provider per query, or the user can force one.

[![CI](https://github.com/Shyzkanza/mcp-location/actions/workflows/ci.yml/badge.svg)](https://github.com/Shyzkanza/mcp-location/actions/workflows/ci.yml)
[![Release](https://github.com/Shyzkanza/mcp-location/actions/workflows/release.yml/badge.svg)](https://github.com/Shyzkanza/mcp-location/actions/workflows/release.yml)
[![npm version](https://img.shields.io/npm/v/@shyzus/mcp-geocrafter)](https://www.npmjs.com/package/@shyzus/mcp-geocrafter)
[![npm downloads](https://img.shields.io/npm/dm/@shyzus/mcp-geocrafter?cacheSeconds=3600)](https://www.npmjs.com/package/@shyzus/mcp-geocrafter)
[![Website Status](https://img.shields.io/website?url=https%3A%2F%2Fgeocrafter.rankorr.red%2Fhealth&label=API)](https://geocrafter.rankorr.red/health)
![Node](https://img.shields.io/badge/node-20%2B-green)
![TypeScript](https://img.shields.io/badge/TypeScript-5.3-blue)
![MCP](https://img.shields.io/badge/MCP-2025--11--25-orange)
![ChatGPT](https://img.shields.io/badge/ChatGPT-MCP-purple)
![Google](https://img.shields.io/badge/Google%20Geocoding-supported-4285F4)
![Photon](https://img.shields.io/badge/Photon%20OSM-supported-7EB900)

---

## ⚠️ Disclaimer

**This project is independent and unofficial.**

- ❌ **Not affiliated** with Google, OpenStreetMap, Photon or Komoot
- ❌ **Not sponsored** by these organizations
- ✅ Uses [Google Geocoding API](https://developers.google.com/maps/documentation/geocoding) (10k free requests/month)
- ✅ Uses **public data** from the [Photon API](https://photon.komoot.io/) (OpenStreetMap)
- ✅ Educational and practical purpose project

---

## 🎯 What is it?

This application allows **ChatGPT** and other MCP clients to access geocoding services with a **clean, modular architecture** that serves as a template for future MCP servers.

### ✨ Features

- 🔍 **Address to GPS** - `search_address_google` (recommended) + `search_address_photon` (fuzzy matching)
- 📍 **GPS to Address** - `reverse_geocode_google` (recommended) + `reverse_geocode_photon`
- 🔄 **Multi-Provider** - Dedicated tools per provider — the LLM picks the right one automatically
- 🔗 **Geohash Encoding/Decoding** - Convert coordinates to geohash strings for location deduplication
- 📏 **Distance Calculation** - Haversine formula to compute exact distance between two GPS points
- 🏗️ **Modular Architecture** - Clean separation of concerns, reusable for future MCP servers
- 🔌 **Dual Mode** - Works with ChatGPT (HTTP) and IDEs (stdio)
- 🗺️ **GeoJSON Map Viewer** - Render interactive maps inside ChatGPT with fullscreen controls (Apps SDK)

### 🔄 Providers

| Provider | Best for | Limitations |
|----------|----------|-------------|
| **Google** (recommended) | POIs, businesses, intent-based queries ("gare ales france") | Requires API key, 10k free/month |
| **Photon** | Typo-tolerant search on place/street names, no API key needed | Less accurate on POI resolution |

Each provider has its own dedicated tools — the LLM sees both options and picks the right one. Users can also force a provider (e.g. "use Google", "use Photon").

### 💬 Usage examples

In ChatGPT or your IDE, simply ask:

> "What are the coordinates of the Eiffel Tower?"

> "What is the address at coordinates 48.8566, 2.3522?"

> "Encode the Eiffel Tower coordinates as a geohash"

> "What's the distance between Paris and Marseille?"

The LLM will use the MCP server to get the information.

---

## 🏗️ Architecture: MCP Server

### What is an MCP Server?

**MCP (Model Context Protocol)** servers allow you to extend ChatGPT and other LLMs with:
- **Custom tools** (call external APIs)
- **Real-time data** (up-to-date information)

### How does it work?

```
                                                  ┌──────────────┐
                                           ┌────► │   Google     │
┌─────────────┐         ┌──────────────┐   │      │   Geocoding  │
│   ChatGPT   │ ◄─────► │  MCP Server  │ ◄─┤      └──────────────┘
│   / IDE     │  MCP    │  (Node.js)   │   │      ┌──────────────┐
└─────────────┘         └──────────────┘   └────► │   Photon     │
                                                  │   API (OSM)  │
                                                  └──────────────┘
```

1. **ChatGPT/IDE** calls your MCP server via the [Model Context Protocol](https://modelcontextprotocol.io/)
2. **The MCP server** routes the request to the selected geocoding provider (Google or Photon)
3. **The results** are returned in a unified format

### MCP Protocol

MCP (Model Context Protocol) is an open standard created by Anthropic that allows LLMs to access external data and tools securely. It is used by:
- ChatGPT (via Apps SDK)
- Claude Desktop
- Cursor
- Other MCP clients

---

## 🚀 Quick Start

### Use with Cursor / Claude Desktop / Warp

**The easiest way** - Install the npm client that connects to the remote server (Google + Photon providers are both available server-side):

```json
{
  "mcpServers": {
    "mcp-geocrafter": {
      "command": "npx",
      "args": ["-y", "@shyzus/mcp-geocrafter"]
    }
  }
}
```

> This connects to the hosted server at `https://geocrafter.rankorr.red/mcp` which has both Google and Photon providers configured. The LLM picks the best provider per query, or the user can force one.

**Config file locations:**
- **Cursor**: `~/.cursor/mcp.json` (macOS/Linux) or `%APPDATA%\Cursor\mcp.json` (Windows)
- **Claude Desktop**: `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS)
- **Warp**: In Warp AI settings

---

### Google API Key Setup

To use the Google provider, you need a Google API key. There are **two ways** to provide it:

**Option A — Server-side (env var):** Set `GOOGLE_API_KEY` on the server. All clients benefit automatically.

**Option B — Per-request (tool parameter):** Pass `apiKey` in the tool call. Useful for N8N, automation workflows, or when you don't control the server. The key is never logged or returned in responses.

**To get a key:**

1. Go to [Google Cloud Console](https://console.cloud.google.com)
2. Create or select a project
3. **APIs & Services** → **Library** → search **"Geocoding API"** → **Enable**
4. **APIs & Services** → **Credentials** → **Create Credentials** → **API Key**
5. Copy the key

> **Pricing**: First 10,000 requests/month are **free**. Beyond that, ~4.34€/1k requests. [Details](https://developers.google.com/maps/documentation/geocoding/usage-and-billing)

---

### Use with ChatGPT

A production server is available and ready to use!

**Server URL**: `https://geocrafter.rankorr.red/mcp`

#### ChatGPT Configuration

1. **Have a ChatGPT account with subscription** (ChatGPT Plus, Team, or Enterprise)
2. **Open ChatGPT in your browser** → Go to **Settings** (⚙️)
3. **Go to "Apps & Connectors"**
4. **Enable developer mode**:
   - In **"Advanced Settings"**, enable **developer mode**
   - Go back
5. **Create a new application**:
   - The **"Create"** button now appears in the top right
   - Click on it
   - Fill in the form:
     - **Name**: "GeoCrafter" (or another name)
     - **Image**: Add an icon/image (optional)
     - **Server URL**: `https://geocrafter.rankorr.red/mcp`
     - **Authentication**: Select **"None"**
   - Click **"Create"**
6. **The application is now available** in ChatGPT and will activate automatically when you ask ChatGPT to use it

#### Test it!

Ask a question in ChatGPT:
> "What are the coordinates of Paris, France?"

Or to test directly:
> "Use GeoCrafter to find the address at coordinates 48.8566, 2.3522"

---

### For developers - Local installation

```bash
# 1. Clone the project
git clone https://github.com/rankorr/mcp-location.git
cd mcp-location

# 2. Install dependencies
npm install

# 3. Build
npm run build

# 4. Use locally
npx @modelcontextprotocol/inspector node dist/index.js
```

---

## 🧪 Tests

```bash
# Run tests
npm test

# Watch mode
npm run test:watch
```

113 tests across 7 suites:
- `googleClient.test.ts` — Google Geocoding API client, mapping, error handling (23 tests)
- `errors.test.ts` — Error classes, formatting, network detection (17 tests)
- `config.test.ts` — Environment variables, validation, singleton (20 tests)
- `displayGeoJsonMap.test.ts` — GeoJSON parsing, viewport, colors, output (26 tests)
- `geohash.test.ts` — Geohash encode/decode, roundtrip, precision (12 tests)
- `haversine.test.ts` — Haversine distance formula, edge cases, symmetry (8 tests)
- `calculateDistance.test.ts` — Distance tool validation, output format (7 tests)

---

## 📱 Deployment and Development

> **💡 To use the application in ChatGPT**, see the [🚀 Quick Start](#-quick-start) section above for complete instructions.

### Option 1: Local Testing with ngrok (For development)

#### 1. Start the HTTP server

```bash
npm run start:http
```

The server starts on `http://localhost:3000`

#### 2. Expose with ngrok

In a **new terminal**:

```bash
# Install ngrok if necessary
brew install ngrok  # macOS
# or download from https://ngrok.com/download

# Expose port 3000
ngrok http 3000
```

You get a public URL like:
```
https://abc123.ngrok-free.dev
```

**Important**: 
- Note the complete URL: `https://abc123.ngrok-free.dev/mcp` (or just `https://abc123.ngrok-free.dev/` - both work)
- The server uses **Streamable HTTP** transport (modern MCP standard, replaces deprecated SSE)

#### 3. Configure the application in ChatGPT

Follow the configuration instructions in the [🚀 Quick Start](#-quick-start) section, using your ngrok URL (`https://your-url.ngrok-free.dev/mcp`) instead of the production URL.

---

### Option 2: Deploy your own server (For developers)

> **Note**: If you just want to use the application, see the [🚀 Quick Start](#-quick-start) section which uses the production server already available.

#### **CI/CD Pipelines**

Two GitHub Actions workflows:

- **`ci.yml`** — Runs on push/PR to `main`: type check, tests, build
- **`release.yml`** — Runs on tag push (`*.*.*`): tests → GHCR image → Docker Swarm deploy → health check → npm publish

#### **Release Process**

```bash
# 1. Bump version
npm version patch   # 1.0.5 → 1.0.6

# 2. Push with tags
git push origin main --tags
```

The tag push triggers `release.yml` which automatically:
- Builds & pushes the Docker image to GHCR
- Deploys to VPS via SSH + `docker stack deploy`
- Runs health check
- Publishes to npm (if version not already published)

#### **Configure your server in ChatGPT**

Once deployed:
1. Note your server URL: `https://your-domain.com/mcp` (or `/` - both endpoints work)
2. The server uses **Streamable HTTP** transport (modern MCP standard)
3. Follow the instructions in [🚀 Quick Start](#-quick-start)

---

## 🧪 Local Testing (without ChatGPT)

### With Cursor (the IDE you're using)

The MCP server already works in Cursor! Ask me a question about locations and I'll use the server.

### With Claude Desktop

1. Install [Claude Desktop](https://claude.ai/download)

2. Configure in `~/Library/Application Support/Claude/claude_desktop_config.json`:

**Option A — Use the remote server (recommended, no API key needed):**
```json
{
  "mcpServers": {
    "mcp-geocrafter": {
      "command": "npx",
      "args": ["-y", "@shyzus/mcp-geocrafter"]
    }
  }
}
```

**Option B — Run locally with your own Google API key:**
```json
{
  "mcpServers": {
    "mcp-geocrafter": {
      "command": "node",
      "args": [
        "/absolute/path/to/mcp-location/dist/index.js"
      ],
      "env": {
        "GOOGLE_API_KEY": "your-google-api-key",
        "GEOCODING_PROVIDER": "google"
      }
    }
  }
}
```

3. Restart Claude Desktop
4. The MCP icon 🔌 appears in the bottom left

### With the MCP inspector

```bash
npx @modelcontextprotocol/inspector node dist/index.js
```

Opens a web interface to test all tools.

---

## 🗺️ GeoJSON Map Viewer (ChatGPT UI Tool)

`display_geojson_map` is a **ChatGPT-only** tool that returns an interactive Leaflet map embedded inside the conversation. It leverages the OpenAI Apps SDK widget runtime (`text/html+skybridge`) and ships with a dedicated template bundled in this repository.

### Inputs

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `geojson` | `object` \| `string` | ✅ | GeoJSON **FeatureCollection** to render. Accepts either a parsed object (recommended) or a JSON string for compatibility with ChatGPT prompts. |
| `title` | `string` | ❌ | Custom title displayed above the map. Defaults to `Carte GeoJSON`. |
| `description` | `string` | ❌ | Caption shown next to the title (e.g., context or instructions). |
| `highlightColor` | `string` | ❌ | Hex color (e.g., `#2563eb`) applied to outlines, fills and markers. |

### Output

- Inline widget rendered directly in ChatGPT with:
  - **OpenStreetMap tiles + Leaflet overlay**
  - Computed bounding box & auto-fit
  - `Recentrer` button
  - `Agrandir` button (toggles fullscreen inside ChatGPT, matching the requirement “option de l’ouvrir en grand”)
- Lightweight `structuredContent` summary exposed to the model (feature count, geometry types, bounds)
- Full GeoJSON stays inside `_meta`, so it is only consumed by the widget (keeps the model prompt small)

### Example call

```json
{
  "name": "display_geojson_map",
  "arguments": {
    "title": "Stations autour de Lyon",
    "description": "Résultats de places_nearby sur 5 km",
    "geojson": {
      "type": "FeatureCollection",
      "features": [
        {
          "type": "Feature",
          "geometry": { "type": "Point", "coordinates": [4.8357, 45.7640] },
          "properties": { "label": "Lyon Part-Dieu" }
        }
      ]
    }
  }
}
```

> ℹ️ The stdio server (Cursor/Claude Desktop) ignores this tool, which is fine: it is explicitly designed for ChatGPT with UI widgets.

---

## 📂 Project Structure

```
mcp-location/
├── src/
│   ├── config.ts                # Configuration centralisée
│   ├── types.ts                 # Types TypeScript partagés
│   ├── __tests__/
│   │   └── config.test.ts       # Tests config
│   ├── client/
│   │   ├── types.ts             # GeocodingProvider interface
│   │   ├── index.ts             # Provider factory/registry
│   │   ├── googleClient.ts      # Google Geocoding API client
│   │   ├── photonClient.ts      # Photon API client (OSM fuzzy matching)
│   │   └── __tests__/
│   │       └── googleClient.test.ts
│   ├── tools/
│   │   ├── searchAddress.ts     # Tool: adresse → GPS
│   │   ├── reverseGeocode.ts    # Tool: GPS → adresse
│   │   ├── encodeGeohash.ts     # Tool: GPS → geohash
│   │   ├── decodeGeohash.ts     # Tool: geohash → GPS
│   │   ├── calculateDistance.ts # Tool: distance entre 2 points
│   │   ├── displayGeoJsonMap.ts # Tool: GeoJSON → widget UI
│   │   └── __tests__/
│   │       ├── displayGeoJsonMap.test.ts
│   │       └── calculateDistance.test.ts
│   ├── resources/
│   │   └── mapViewerTemplate.ts # Template HTML pour ChatGPT
│   ├── servers/
│   │   ├── stdio.ts             # Serveur stdio (IDEs)
│   │   └── http.ts              # Serveur Streamable HTTP (ChatGPT)
│   ├── utils/
│   │   ├── errors.ts            # Gestion erreurs centralisée
│   │   ├── geohash.ts           # Encode/decode geohash (zero deps)
│   │   ├── haversine.ts         # Distance Haversine (zero deps)
│   │   └── __tests__/
│   │       ├── errors.test.ts
│   │       ├── geohash.test.ts
│   │       └── haversine.test.ts
│   ├── index.ts                 # Entry point stdio
│   ├── http-server.ts           # Entry point HTTP
│   └── http-client.ts           # Client npm
├── .github/workflows/
│   ├── ci.yml                   # CI: tests on push/PR
│   └── release.yml              # Release: GHCR + deploy + npm
├── Dockerfile                   # Multi-stage Docker (node:20-alpine)
├── docker-compose.yml           # Docker Swarm stack
├── vitest.config.ts             # Vitest configuration
├── package.json
├── tsconfig.json
└── README.md
```

---

## 🛠️ Available Commands

> 📖 **Full documentation**: [COMMANDS.md](./COMMANDS.md)

### Quick Reference

```bash
# 🌟 Recommended for ChatGPT development (2 terminals)
npm run tunnel           # Terminal 1: ngrok (keep running)
npm run dev              # Terminal 2: Dev server with hot-reload

# Alternative: All-in-one
npm run dev:tunnel       # Dev + ngrok in parallel

# Testing
npm run inspect          # Launch MCP Inspector
npm run health           # Health check

# Build & Production
npm run build            # Compile TypeScript
npm run rebuild          # Clean + Build
npm run build:start      # Build then start

# Utilities
npm run kill             # Kill process on port 3000
npm run kill:tunnel      # Kill ngrok
```

### Cursor Commands

Available via **Cmd+Shift+P**:
- `dev-server` - Dev with hot-reload (recommended)
- `tunnel-only` - Launch ngrok (keep running)
- `mcp-inspector` - Launch MCP Inspector
- `build` / `rebuild` / `clean`
- `kill-server` / `kill-tunnel`

See [COMMANDS.md](./COMMANDS.md) for the complete list.

---

## 🔧 Advanced Configuration

### Environment variables

Create a `.env` file:

```bash
PORT=3000                          # HTTP server port
NODE_ENV=production                # Environment
GEOCODING_PROVIDER=google          # Default provider: "photon" (default) or "google"
GOOGLE_API_KEY=AIzaSy...           # Required for Google provider (10k free requests/month)
PHOTON_BASE_URL=https://photon.komoot.io  # Optional (default: Komoot's public instance)
USER_AGENT=MyApp/1.0              # Optional
CORS_ORIGIN=*                      # CORS origin (default: * in dev, https://chatgpt.com in prod)
```

### Providers configuration

- **Google**: Two options to provide the API key:
  - **Server-side**: Set `GOOGLE_API_KEY` environment variable — all clients benefit automatically
  - **Per-request**: Pass `apiKey` parameter in the tool call — for N8N, automations, or when you don't control the server
- **Photon**: Always available, no configuration needed. You can optionally self-host (set `PHOTON_BASE_URL`).
- Each provider has **dedicated tools** (`search_address_google`, `search_address_photon`, etc.) — no `provider` parameter needed.
- The `apiKey` parameter on Google tools is never logged, never stored, never returned in responses.

---

## 🏗️ Architecture Details

This project serves as a **template/base** for future MCP servers with a clean, modular architecture:

### Separation of Concerns

- **`config.ts`**: Environment variables, constants, validation
- **`types.ts`**: Shared TypeScript interfaces
- **`client/`**: External API abstraction (Google, Photon) with provider interface + factory
- **`tools/`**: Business logic (validation, transformation, formatting)
- **`servers/`**: MCP implementation (stdio/Streamable HTTP), reuses tools
- **`utils/`**: Custom error classes, geohash encode/decode, Haversine distance (zero dependencies)

See [CONTEXT.md](CONTEXT.md) for detailed architecture documentation.

---

## 📚 Resources & Documentation

### Project Documentation

- [CONTEXT.md](./CONTEXT.md) - Project memory (status, decisions, changelog)
- [COMMANDS.md](./COMMANDS.md) - All npm scripts and Cursor commands
- [OPENAI_APPS_SDK_REFERENCE.md](./OPENAI_APPS_SDK_REFERENCE.md) - Complete SDK reference guide

### Official documentation

- [OpenAI Apps SDK](https://developers.openai.com/apps-sdk) - Complete ChatGPT Apps guide
- [Apps SDK - MCP Server](https://developers.openai.com/apps-sdk/build/mcp-server) - Server config
- [Model Context Protocol](https://modelcontextprotocol.io/) - MCP spec
- [MCP SDK TypeScript](https://github.com/modelcontextprotocol/typescript-sdk) - Node.js SDK
- [Photon API](https://photon.komoot.io/) - Geocoding API (OpenStreetMap + Elasticsearch)

### Community

- [MCP Servers Repository](https://github.com/modelcontextprotocol/servers) - Official examples
- [OpenAI Apps Examples](https://github.com/openai/chatgpt-apps-examples) - App examples

---

## 🐛 Debugging & Troubleshooting

### Server won't start

```bash
# Check that Node.js is installed
node --version  # Must be 20+

# Check that dependencies are installed
npm install

# Full rebuild
npm run build
```

### UI doesn't display in ChatGPT

1. **Check ngrok logs** - See if ChatGPT is making requests
2. **Check the server** - `http://localhost:3000/health` must respond
3. **Refresh the connector** in ChatGPT (Settings → Apps → Refresh)
4. **Check the CORS** - Allowed domains in `src/servers/http.ts`

### CORS errors

The server allows all origins in dev. In production, restrict in `src/servers/http.ts`:

```typescript
res.setHeader('Access-Control-Allow-Origin', 'https://chatgpt.com');
```

### Logs

Server logs display in the terminal. For more details:

```typescript
console.log('MCP Request:', jsonRpcRequest.method);
```

---

## 🚀 Use This Project as a Template

This project is a **complete template** for creating your own ChatGPT apps with a clean architecture.

### To create your own app:

1. **Duplicate this project**
2. **Replace the Photon API** with your API
3. **Modify the tools** in `src/tools/`
4. **Customize the configuration** in `src/config.ts`
5. **Deploy**!

### Possible app examples

- 🎬 **Cinema** - Movie search and showtimes
- 🍽️ **Restaurants** - Reservations with menu
- 🏨 **Hotels** - Search and availability
- 📦 **Delivery** - Package tracking
- 📰 **News** - Articles with integrated reader
- 🎵 **Music** - Audio player in ChatGPT
- 📊 **Analytics** - Charts and dashboards

The possibilities are endless! 🚀

---

## 📝 License

MIT - Use freely for your personal or commercial projects.

---

## 🙏 Credits & Attributions

- **Geocoding Data** - [Google Geocoding API](https://developers.google.com/maps/documentation/geocoding) and [Photon API](https://photon.komoot.io/) by [Komoot](https://www.komoot.com/) (OpenStreetMap data)
- **MCP Protocol** - [Anthropic](https://www.anthropic.com/)
- **Apps SDK** - [OpenAI](https://openai.com/)

### Data & Licenses

- Google Geocoding data is provided under [Google Maps Platform Terms of Service](https://cloud.google.com/maps-platform/terms)
- Photon/OpenStreetMap data is provided under the Open Database License (ODbL)

---

## 📞 Support

For any questions:
- 📖 Check the [Apps SDK documentation](https://developers.openai.com/apps-sdk)
- 💬 Open an issue on GitHub
- 📧 Contact the team

---

**Have fun with your ChatGPT app! 📍✨**