@pipeworx/mcp-maptiler 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Pipeworx
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,60 @@
1
+ # mcp-maptiler
2
+
3
+ MapTiler MCP.
4
+
5
+ Part of [Pipeworx](https://pipeworx.io) — an MCP gateway connecting AI agents to 965+ live data sources.
6
+
7
+ ## Tools
8
+
9
+ | Tool | Description |
10
+ |------|-------------|
11
+ | `geocode` | "Geocode [address]" / "find coordinates of [place]" / "lat lng for [city]" / "search OpenStreetMap-backed places" — forward geocoding via MapTiler (OpenStreetMap-curated). Returns ranked candidates with lat/lng, address components, and feature IDs for re-lookup via geocode_by_id. Alternative to Mapbox/Google geocoders when you want OSM data. |
12
+ | `geocode_reverse` | "What address is at [lat,lng]" / "reverse geocode [coords]" / "what place is at this point" — reverse geocoding (coordinates → address / locality / region) via MapTiler. |
13
+ | `elevation_polyline` | "Elevation profile along [route]" / "topographic profile of [path]" / "how hilly is this trail" — elevation samples along a polyline (sequence of lat/lng). Use for hiking elevation gain, cycling grade, trail planning. |
14
+ | `static_map_url` | "Static map image of [location]" / "embed a map of [coords]" / "map thumbnail PNG" / "screenshot of map" — returns a MapTiler static-tile image URL for embedding in slack, docs, emails, dashboards. Pass style + coords + zoom + width/height; returns a fetchable PNG URL. No interactive JS required. |
15
+ | `coordinates_convert` | "Convert WGS84 lat/lng to [other CRS]" / "reproject coordinates" / "EPSG:4326 → EPSG:[X]" / "Web Mercator coordinates" — Coordinate Reference System (CRS) reprojection. Use to convert standard lat/lng (EPSG:4326) into projected systems like Web Mercator (3857), UTM zones, state plane, etc. |
16
+
17
+ ## Quick Start
18
+
19
+ Add to your MCP client (Claude Desktop, Cursor, Windsurf, etc.):
20
+
21
+ ```json
22
+ {
23
+ "mcpServers": {
24
+ "maptiler": {
25
+ "url": "https://gateway.pipeworx.io/maptiler/mcp"
26
+ }
27
+ }
28
+ }
29
+ ```
30
+
31
+ Or connect to the full Pipeworx gateway for access to all 965+ data sources:
32
+
33
+ ```json
34
+ {
35
+ "mcpServers": {
36
+ "pipeworx": {
37
+ "url": "https://gateway.pipeworx.io/mcp"
38
+ }
39
+ }
40
+ }
41
+ ```
42
+
43
+ ## Using with ask_pipeworx
44
+
45
+ Instead of calling tools directly, you can ask questions in plain English:
46
+
47
+ ```
48
+ ask_pipeworx({ question: "your question about Maptiler data" })
49
+ ```
50
+
51
+ The gateway picks the right tool and fills the arguments automatically.
52
+
53
+ ## More
54
+
55
+ - [All tools and guides](https://github.com/pipeworx-io/examples)
56
+ - [pipeworx.io](https://pipeworx.io)
57
+
58
+ ## License
59
+
60
+ MIT
package/package.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "@pipeworx/mcp-maptiler",
3
+ "version": "0.1.0",
4
+ "description": "MapTiler MCP.",
5
+ "type": "module",
6
+ "main": "src/index.ts",
7
+ "types": "src/index.ts",
8
+ "keywords": ["mcp", "mcp-server", "model-context-protocol", "pipeworx", "maptiler"],
9
+ "license": "MIT",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "https://github.com/pipeworx-io/mcp-maptiler"
13
+ },
14
+ "scripts": {
15
+ "typecheck": "tsc --noEmit"
16
+ },
17
+ "devDependencies": {
18
+ "typescript": "^5.7.0"
19
+ }
20
+ }
package/server.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3
+ "name": "io.github.pipeworx-io/maptiler",
4
+ "title": "Maptiler",
5
+ "description": "MapTiler MCP.",
6
+ "version": "0.1.0",
7
+ "websiteUrl": "https://pipeworx.io/packs/maptiler",
8
+ "repository": {
9
+ "url": "https://github.com/pipeworx-io/mcp-maptiler",
10
+ "source": "github"
11
+ },
12
+ "remotes": [
13
+ {
14
+ "type": "streamable-http",
15
+ "url": "https://gateway.pipeworx.io/maptiler/mcp"
16
+ }
17
+ ]
18
+ }
package/src/index.ts ADDED
@@ -0,0 +1,172 @@
1
+ interface McpToolDefinition {
2
+ name: string;
3
+ description: string;
4
+ inputSchema: {
5
+ type: 'object';
6
+ properties: Record<string, unknown>;
7
+ required?: string[];
8
+ };
9
+ }
10
+
11
+ interface McpToolExport {
12
+ tools: McpToolDefinition[];
13
+ callTool: (name: string, args: Record<string, unknown>) => Promise<unknown>;
14
+ meter?: { credits: number };
15
+ cost?: Record<string, unknown>;
16
+ provider?: string;
17
+ }
18
+
19
+ /**
20
+ * MapTiler MCP.
21
+ */
22
+
23
+
24
+ const BASE = 'https://api.maptiler.com';
25
+ const UA = 'pipeworx-mcp-maptiler/1.0 (+https://pipeworx.io)';
26
+
27
+ const tools: McpToolExport['tools'] = [
28
+ {
29
+ name: 'geocode',
30
+ description: '"Geocode [address]" / "find coordinates of [place]" / "lat lng for [city]" / "search OpenStreetMap-backed places" — forward geocoding via MapTiler (OpenStreetMap-curated). Returns ranked candidates with lat/lng, address components, and feature IDs for re-lookup via geocode_by_id. Alternative to Mapbox/Google geocoders when you want OSM data.',
31
+ inputSchema: {
32
+ type: 'object',
33
+ properties: {
34
+ query: { type: 'string' },
35
+ language: { type: 'string' },
36
+ limit: { type: 'number' },
37
+ bbox: { type: 'string' },
38
+ proximity: { type: 'string' },
39
+ country: { type: 'string' },
40
+ types: { type: 'string' },
41
+ autocomplete: { type: 'boolean' },
42
+ fuzzyMatch: { type: 'boolean' },
43
+ },
44
+ required: ['query'],
45
+ },
46
+ },
47
+ {
48
+ name: 'geocode_reverse',
49
+ description: '"What address is at [lat,lng]" / "reverse geocode [coords]" / "what place is at this point" — reverse geocoding (coordinates → address / locality / region) via MapTiler.',
50
+ inputSchema: {
51
+ type: 'object',
52
+ properties: { lon: { type: 'number' }, lat: { type: 'number' }, language: { type: 'string' }, limit: { type: 'number' }, types: { type: 'string' } },
53
+ required: ['lon', 'lat'],
54
+ },
55
+ },
56
+ { name: 'geocode_by_id', description: 'Re-fetch a MapTiler geocoding feature by its stable ID (returned in geocode / geocode_reverse results). Use to refresh or re-localize a previously discovered place.', inputSchema: { type: 'object', properties: { id: { type: 'string' }, language: { type: 'string' } }, required: ['id'] } },
57
+ { name: 'elevation', description: '"Elevation at [coords]" / "altitude at [point]" / "how high is [location]" / "height above sea level" — elevation in meters above sea level at a single point via MapTiler\'s SRTM/Maxar dataset.', inputSchema: { type: 'object', properties: { lon: { type: 'number' }, lat: { type: 'number' } }, required: ['lon', 'lat'] } },
58
+ {
59
+ name: 'elevation_polyline',
60
+ description: '"Elevation profile along [route]" / "topographic profile of [path]" / "how hilly is this trail" — elevation samples along a polyline (sequence of lat/lng). Use for hiking elevation gain, cycling grade, trail planning.',
61
+ inputSchema: { type: 'object', properties: { coordinates: { type: 'array', items: { type: 'array', items: { type: 'number' } } } }, required: ['coordinates'] },
62
+ },
63
+ {
64
+ name: 'static_map_url',
65
+ description: '"Static map image of [location]" / "embed a map of [coords]" / "map thumbnail PNG" / "screenshot of map" — returns a MapTiler static-tile image URL for embedding in slack, docs, emails, dashboards. Pass style + coords + zoom + width/height; returns a fetchable PNG URL. No interactive JS required.',
66
+ inputSchema: {
67
+ type: 'object',
68
+ properties: {
69
+ style: { type: 'string' },
70
+ lon: { type: 'number' },
71
+ lat: { type: 'number' },
72
+ zoom: { type: 'number' },
73
+ width: { type: 'number' },
74
+ height: { type: 'number' },
75
+ retina: { type: 'boolean' },
76
+ marker: { type: 'string' },
77
+ attribution: { type: 'string' },
78
+ },
79
+ required: ['style', 'lon', 'lat', 'zoom', 'width', 'height'],
80
+ },
81
+ },
82
+ {
83
+ name: 'coordinates_convert',
84
+ description: '"Convert WGS84 lat/lng to [other CRS]" / "reproject coordinates" / "EPSG:4326 → EPSG:[X]" / "Web Mercator coordinates" — Coordinate Reference System (CRS) reprojection. Use to convert standard lat/lng (EPSG:4326) into projected systems like Web Mercator (3857), UTM zones, state plane, etc.',
85
+ inputSchema: {
86
+ type: 'object',
87
+ properties: { coordinates: { type: 'array', items: { type: 'array', items: { type: 'number' } } }, target_crs: { type: 'number' } },
88
+ required: ['coordinates', 'target_crs'],
89
+ },
90
+ },
91
+ { name: 'tiles_json', description: 'TileJSON spec metadata for a MapTiler tileset (zoom range, bounds, layer schema). Specialist tool for GIS integrators — most users want geocode / static_map_url instead.', inputSchema: { type: 'object', properties: { tileset: { type: 'string' } }, required: ['tileset'] } },
92
+ ];
93
+
94
+ async function callTool(name: string, args: Record<string, unknown>): Promise<unknown> {
95
+ const apiKey = (args._apiKey as string | undefined)?.trim();
96
+ if (!apiKey) throw new Error('MapTiler requires an API key. Set PLATFORM_MAPTILER_KEY or pass ?_apiKey=… (free at https://cloud.maptiler.com/account/keys/).');
97
+ const get = async (url: string) => {
98
+ const res = await fetch(url, { headers: { Accept: 'application/json', 'User-Agent': UA } });
99
+ if (res.status === 401 || res.status === 403) throw new Error('MapTiler: invalid API key.');
100
+ if (!res.ok) throw new Error(`MapTiler: ${res.status}`);
101
+ return res.json();
102
+ };
103
+ const reqStr = (k: string, ex: string) => {
104
+ const v = args[k];
105
+ if (typeof v !== 'string' || !v.trim()) throw new Error(`Required argument "${k}" is missing. Pass a string like ${ex}.`);
106
+ return v;
107
+ };
108
+ const reqNum = (k: string, ex: string) => {
109
+ const v = args[k];
110
+ if (v == null || typeof v !== 'number') throw new Error(`Required argument "${k}" is missing. Pass a number like ${ex}.`);
111
+ return v;
112
+ };
113
+ switch (name) {
114
+ case 'geocode': {
115
+ const q = encodeURIComponent(reqStr('query', '"Paris"'));
116
+ const p = new URLSearchParams({ key: apiKey });
117
+ for (const k of ['language', 'bbox', 'proximity', 'country', 'types'] as const) if (args[k]) p.set(k, String(args[k]));
118
+ if (args.limit != null) p.set('limit', String(args.limit));
119
+ if (args.autocomplete != null) p.set('autocomplete', args.autocomplete ? 'true' : 'false');
120
+ if (args.fuzzyMatch != null) p.set('fuzzyMatch', args.fuzzyMatch ? 'true' : 'false');
121
+ return get(`${BASE}/geocoding/${q}.json?${p}`);
122
+ }
123
+ case 'geocode_reverse': {
124
+ const lon = reqNum('lon', '2.349');
125
+ const lat = reqNum('lat', '48.864');
126
+ const p = new URLSearchParams({ key: apiKey });
127
+ if (args.language) p.set('language', String(args.language));
128
+ if (args.limit != null) p.set('limit', String(args.limit));
129
+ if (args.types) p.set('types', String(args.types));
130
+ return get(`${BASE}/geocoding/${lon},${lat}.json?${p}`);
131
+ }
132
+ case 'geocode_by_id': {
133
+ const id = encodeURIComponent(reqStr('id', '"place.1234567890"'));
134
+ const p = new URLSearchParams({ key: apiKey });
135
+ if (args.language) p.set('language', String(args.language));
136
+ return get(`${BASE}/geocoding/${id}.json?${p}`);
137
+ }
138
+ case 'elevation': {
139
+ const lon = reqNum('lon', '2.349');
140
+ const lat = reqNum('lat', '48.864');
141
+ return get(`${BASE}/elevation/v1/single?lng=${lon}&lat=${lat}&key=${encodeURIComponent(apiKey)}`);
142
+ }
143
+ case 'elevation_polyline': {
144
+ const coords = (args.coordinates as number[][]).map(([lon, lat]) => `${lon},${lat}`).join('|');
145
+ return get(`${BASE}/elevation/v1/polyline?points=${encodeURIComponent(coords)}&key=${encodeURIComponent(apiKey)}`);
146
+ }
147
+ case 'static_map_url': {
148
+ const style = reqStr('style', '"streets-v2"');
149
+ const lon = reqNum('lon', '2.349');
150
+ const lat = reqNum('lat', '48.864');
151
+ const zoom = reqNum('zoom', '12');
152
+ const w = reqNum('width', '600');
153
+ const h = reqNum('height', '400');
154
+ const retina = args.retina ? '@2x' : '';
155
+ const p = new URLSearchParams({ key: apiKey });
156
+ if (args.marker) p.set('marker', String(args.marker));
157
+ if (args.attribution) p.set('attribution', String(args.attribution));
158
+ return { url: `${BASE}/maps/${encodeURIComponent(style)}/static/${lon},${lat},${zoom}/${w}x${h}${retina}.png?${p}`, note: 'PNG binary; open in a browser or fetch as bytes.' };
159
+ }
160
+ case 'coordinates_convert': {
161
+ const coords = (args.coordinates as number[][]).map(([x, y]) => `${x},${y}`).join('|');
162
+ const target = reqNum('target_crs', '3857');
163
+ return get(`${BASE}/coordinates/transform/${encodeURIComponent(coords)}.json?key=${encodeURIComponent(apiKey)}&s_srs=4326&t_srs=${target}`);
164
+ }
165
+ case 'tiles_json':
166
+ return get(`${BASE}/tiles/${encodeURIComponent(reqStr('tileset', '"streets-v2"'))}/tiles.json?key=${encodeURIComponent(apiKey)}`);
167
+ default:
168
+ throw new Error(`Unknown tool: ${name}`);
169
+ }
170
+ }
171
+
172
+ export default { tools, callTool, meter: { credits: 1 } } satisfies McpToolExport;
package/tsconfig.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "strict": true,
7
+ "esModuleInterop": true,
8
+ "skipLibCheck": true,
9
+ "outDir": "dist",
10
+ "rootDir": "src",
11
+ "declaration": true
12
+ },
13
+ "include": ["src"]
14
+ }