Skip to content

Commit 35fc8ed

Browse files
committed
feat(server): init Geocoding MCP server
1 parent c69bd81 commit 35fc8ed

File tree

16 files changed

+893
-1
lines changed

16 files changed

+893
-1
lines changed

.github/workflows/lint.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: Lint
2+
3+
on:
4+
pull_request:
5+
6+
jobs:
7+
lint:
8+
runs-on: ubuntu-latest
9+
10+
steps:
11+
- name: Checkout repository
12+
uses: actions/checkout@v4
13+
14+
- name: Setup Bun
15+
uses: oven-sh/setup-bun@v1
16+
with:
17+
bun-version: latest
18+
19+
- name: Install dependencies
20+
run: bun install
21+
22+
- name: Run Lint
23+
run: bun run lint

.github/workflows/release.yml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
name: Release
2+
3+
on:
4+
release:
5+
types:
6+
- published
7+
8+
jobs:
9+
release:
10+
name: Release
11+
runs-on: ubuntu-latest
12+
steps:
13+
- name: Checkout Repo
14+
uses: actions/checkout@v3
15+
16+
- name: Set env
17+
run: echo "VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
18+
19+
- name: Setup Bun
20+
uses: oven-sh/setup-bun@v1
21+
with:
22+
bun-version: latest
23+
24+
- name: Set package version
25+
run: |
26+
echo $(jq --arg v "${{ env.VERSION }}" '(.version) = $v' package.json) > package.json
27+
28+
- name: Update version in source file
29+
run: |
30+
sed -i "s/version: \"[0-9]*\.[0-9]*\.[0-9]*\"/version: \"${{ env.VERSION }}\"/" src/index.ts
31+
32+
- name: Install Dependencies
33+
run: bun install
34+
35+
- name: Build
36+
run: bun run build
37+
38+
- name: Publish
39+
if: ${{ !github.event.release.prerelease }}
40+
env:
41+
NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}
42+
run: |
43+
bun publish
44+
45+
- name: Publish release candidate
46+
if: ${{ github.event.release.prerelease }}
47+
env:
48+
NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}
49+
run: |
50+
bun publish --tag=canary

.gitignore

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# dependencies (bun install)
2+
node_modules
3+
4+
# output
5+
out
6+
dist
7+
*.tgz
8+
9+
# code coverage
10+
coverage
11+
*.lcov
12+
13+
# logs
14+
logs
15+
_.log
16+
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
17+
18+
# dotenv environment variable files
19+
.env
20+
.env.development.local
21+
.env.test.local
22+
.env.production.local
23+
.env.local
24+
25+
# caches
26+
.eslintcache
27+
.cache
28+
*.tsbuildinfo
29+
30+
# IntelliJ based IDEs
31+
.idea
32+
33+
# Finder (MacOS) folder config
34+
.DS_Store
35+
36+
# Trae
37+
.trae

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2025 Geocoding AI
3+
Copyright (c) 2025 Srihari Thalla
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
![CodeRabbit Pull Request Reviews](https://img.shields.io/coderabbit/prs/github/geocoding-ai/mcp?utm_source=oss&utm_medium=github&utm_campaign=geocoding-ai%2Fmcp&labelColor=171717&color=FF570A&link=https%3A%2F%2Fcoderabbit.ai&label=CodeRabbit+Reviews)
2+
3+
# Geocoding MCP Server
4+
5+
This is a Model Context Protocol (MCP) server that provides geocoding services by integrating with the Nominatim API.
6+
7+
## Installation
8+
9+
### Requirements
10+
- Node.js >= 18.0.0
11+
- Cursor, Windsurf, Claude Desktop, Trae or another MCP Client
12+
13+
## Install in Claude Desktop
14+
Add this to your Claude Desktop `claude_desktop_config.json` file. See [Claude Desktop MCP docs](https://modelcontextprotocol.io/quickstart/user) for more info.
15+
16+
```json
17+
{
18+
"mcpServers": {
19+
"geocoding": {
20+
"command": "npx",
21+
"args": [
22+
"-y",
23+
"@geocoding-ai/mcp"
24+
]
25+
}
26+
}
27+
}
28+
```
29+
30+
## License
31+
32+
Codebase: [MIT](./LICENSE)
33+
34+
Documentation: [GPLv2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) / [Nominatim developer community](https://github.com/osm-search/Nominatim) / [Nominatim Manual](https://nominatim.org/release-docs/latest/)

bun.lock

Lines changed: 441 additions & 0 deletions
Large diffs are not rendered by default.

eslint.config.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// @ts-check
2+
3+
import eslint from '@eslint/js'
4+
import tseslint from 'typescript-eslint'
5+
6+
export default tseslint.config(
7+
{
8+
extends: [
9+
eslint.configs.recommended,
10+
tseslint.configs.recommended,
11+
],
12+
rules: {
13+
'semi': ['error', 'never'],
14+
'@typescript-eslint/no-explicit-any': 'off',
15+
'@typescript-eslint/no-unused-vars': 'off',
16+
'comma-dangle': ['error', 'always-multiline'],
17+
},
18+
},
19+
)

package.json

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"name": "@geocoding-ai/mcp",
3+
"main": "./dist/index.js",
4+
"module": "./dist/index.js",
5+
"type": "module",
6+
"version": "0.1.0",
7+
"files": [
8+
"dist"
9+
],
10+
"private": false,
11+
"publishConfig": {
12+
"access": "public",
13+
"tag": "latest"
14+
},
15+
"scripts": {
16+
"build": "tsc",
17+
"inspect": "bunx @modelcontextprotocol/inspector node dist/index.js",
18+
"watch": "tsc --watch",
19+
"lint": "eslint src"
20+
},
21+
"devDependencies": {
22+
"@eslint/js": "^9.28.0",
23+
"@types/axios": "^0.14.4",
24+
"@types/bun": "latest",
25+
"eslint": "^9.28.0",
26+
"typescript-eslint": "^8.33.0"
27+
},
28+
"peerDependencies": {
29+
"typescript": "^5.8.3"
30+
},
31+
"dependencies": {
32+
"@modelcontextprotocol/sdk": "^1.12.1",
33+
"axios": "^1.9.0"
34+
}
35+
}

src/clients/nominatimClient.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import axios from 'axios'
2+
import type { ReverseGeocodeParams } from '../types/reverseGeocodeTypes.js'
3+
import type { GeocodeParams } from '../types/geocodeTypes.js'
4+
5+
const nominatimClient = axios.create({
6+
baseURL: 'https://nominatim.geocoding.ai/',
7+
headers: {
8+
'User-Agent': 'GeocodingMCP/1.0',
9+
},
10+
})
11+
12+
const parseResult = (result: any[]) => {
13+
result.forEach((item: any) => {
14+
delete item.licence
15+
})
16+
17+
return result
18+
}
19+
20+
export const geocodeAddress = async (params: GeocodeParams) => {
21+
const response = await nominatimClient.get('search', { params })
22+
return parseResult(response.data)
23+
}
24+
25+
export const reverseGeocode = async (params: ReverseGeocodeParams) => {
26+
const response = await nominatimClient.get('reverse', { params })
27+
return parseResult([response.data])
28+
}

src/index.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"
2+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
3+
import registerGeocodeTool from "./tools/geocode.js"
4+
import registerReverseGeocodeTool from "./tools/reverseGeocode.js"
5+
6+
const server = new McpServer({
7+
name: "geocoding",
8+
version: "0.1.0",
9+
description: "Geocoding API",
10+
})
11+
12+
registerGeocodeTool(server)
13+
registerReverseGeocodeTool(server)
14+
15+
async function main() {
16+
const transport = new StdioServerTransport()
17+
await server.connect(transport)
18+
console.error("Geocoding API MCP Server running on stdio")
19+
}
20+
21+
main().catch((error) => {
22+
console.error("Fatal error in main():", error)
23+
process.exit(1)
24+
})

0 commit comments

Comments
 (0)