Skip to content

Commit e2b73d5

Browse files
Reapply "Merge pull request #33 from mapbox/output_schemas"
This reverts commit 4853cac.
1 parent 1edcadc commit e2b73d5

File tree

83 files changed

+3819
-1373
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+3819
-1373
lines changed

cspell.config.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"version": "0.2",
3+
"language": "en",
4+
"words": [
5+
"bbox",
6+
"denoise",
7+
"isochrone",
8+
"mapbox",
9+
"mmss",
10+
"tilequery"
11+
],
12+
"ignorePaths": [
13+
"node_modules",
14+
"dist"
15+
]
16+
}

package-lock.json

Lines changed: 1033 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,18 @@
1010
"mapbox-mcp-devkit": "dist/esm/index.js"
1111
},
1212
"scripts": {
13-
"lint": "eslint \"./src/**/*.{ts,tsx}\" \"./test/**/*.{ts,tsx}\"",
14-
"lint:fix": "eslint \"./src/**/*.{ts,tsx}\" \"./test/**/*.{ts,tsx}\" --fix",
15-
"fix-lint": "npm run lint:fix && npm run format:fix",
13+
"build": "npm run prepare && tshy && npm run generate-version && node scripts/add-shebang.cjs",
1614
"format": "prettier --check \"./src/**/*.{ts,tsx,js,json,md}\" \"./test/**/*.{ts,tsx,js,json,md}\"",
1715
"format:fix": "prettier --write \"./src/**/*.{ts,tsx,js,json,md}\" \"./test/**/*.{ts,tsx,js,json,md}\"",
18-
"prepare": "husky && node .husky/setup-hooks.js",
19-
"test": "vitest",
20-
"build": "npm run prepare && npm run sync-manifest && tshy && npm run generate-version && node scripts/build-helpers.cjs copy-json && node scripts/add-shebang.cjs",
2116
"generate-version": "node scripts/build-helpers.cjs generate-version",
17+
"inspect:build": "npm run build && npx @modelcontextprotocol/inspector -e MAPBOX_ACCESS_TOKEN=\"$MAPBOX_ACCESS_TOKEN\" node dist/esm/index.js",
18+
"inspect:dev": "npx @modelcontextprotocol/inspector -e MAPBOX_ACCESS_TOKEN=\"$MAPBOX_ACCESS_TOKEN\" npx -y tsx src/index.ts",
19+
"lint": "eslint \"./src/**/*.{ts,tsx}\" \"./test/**/*.{ts,tsx}\"",
20+
"lint:fix": "eslint \"./src/**/*.{ts,tsx}\" \"./test/**/*.{ts,tsx}\" --fix",
21+
"prepare": "husky && node .husky/setup-hooks.js",
22+
"spellcheck": "cspell \"*.md\" \"src/**/*.ts\" \"test/**/*.ts\"",
2223
"sync-manifest": "node scripts/sync-manifest-version.cjs",
23-
"dev": "tsc -p tsconfig.json --watch",
24-
"dev:inspect": "npx @modelcontextprotocol/inspector -e MAPBOX_ACCESS_TOKEN=\"$MAPBOX_ACCESS_PRIVATE_TOKEN\" npx -y tsx src/index.ts"
24+
"test": "vitest"
2525
},
2626
"lint-staged": {
2727
"*.{js,jsx,ts,tsx}": "eslint --fix",
@@ -53,6 +53,7 @@
5353
"@typescript-eslint/eslint-plugin": "^8.0.0",
5454
"@typescript-eslint/parser": "^8.0.0",
5555
"@vitest/coverage-istanbul": "^3.2.4",
56+
"cspell": "^9.2.1",
5657
"eslint": "^9.0.0",
5758
"eslint-config-prettier": "^10.1.8",
5859
"eslint-plugin-n": "^17.21.3",

src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// Copyright (c) Mapbox, Inc.
2+
// Licensed under the MIT License.
3+
14
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
25
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
36
import { parseToolConfigFromArgs, filterTools } from './config/toolConfig.js';

src/schemas/style.ts

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
// Copyright (c) Mapbox, Inc.
2+
// Licensed under the MIT License.
3+
4+
import { z } from 'zod';
5+
6+
// Basic types
7+
const ColorSchema = z
8+
.string()
9+
.describe('Color as hex, rgb, rgba, hsl, or hsla');
10+
const CoordinatesSchema = z.tuple([z.number(), z.number()]);
11+
12+
// Transition schema
13+
const TransitionSchema = z.object({
14+
duration: z.number().optional(),
15+
delay: z.number().optional()
16+
});
17+
18+
// Light schema
19+
const LightSchema = z.object({
20+
anchor: z.enum(['map', 'viewport']).optional(),
21+
position: z.tuple([z.number(), z.number(), z.number()]).optional(),
22+
color: ColorSchema.optional(),
23+
intensity: z.number().optional()
24+
});
25+
26+
// Lights (3D) schema
27+
const LightsSchema = z.array(
28+
z.object({
29+
id: z.string(),
30+
type: z.enum(['ambient', 'directional']),
31+
properties: z.record(z.any()).optional()
32+
})
33+
);
34+
35+
// Terrain schema
36+
const TerrainSchema = z.object({
37+
source: z.string(),
38+
exaggeration: z.number().optional()
39+
});
40+
41+
// Source schemas
42+
const VectorSourceSchema = z.object({
43+
type: z.literal('vector'),
44+
url: z.string().optional(),
45+
tiles: z.array(z.string()).optional(),
46+
bounds: z.tuple([z.number(), z.number(), z.number(), z.number()]).optional(),
47+
scheme: z.enum(['xyz', 'tms']).optional(),
48+
minzoom: z.number().min(0).max(22).optional(),
49+
maxzoom: z.number().min(0).max(22).optional(),
50+
attribution: z.string().optional(),
51+
promoteId: z.union([z.string(), z.record(z.string())]).optional(),
52+
volatile: z.boolean().optional()
53+
});
54+
55+
const RasterSourceSchema = z.object({
56+
type: z.literal('raster'),
57+
url: z.string().optional(),
58+
tiles: z.array(z.string()).optional(),
59+
bounds: z.tuple([z.number(), z.number(), z.number(), z.number()]).optional(),
60+
minzoom: z.number().min(0).max(22).optional(),
61+
maxzoom: z.number().min(0).max(22).optional(),
62+
tileSize: z.number().optional(),
63+
scheme: z.enum(['xyz', 'tms']).optional(),
64+
attribution: z.string().optional(),
65+
volatile: z.boolean().optional()
66+
});
67+
68+
const RasterDemSourceSchema = z.object({
69+
type: z.literal('raster-dem'),
70+
url: z.string().optional(),
71+
tiles: z.array(z.string()).optional(),
72+
bounds: z.tuple([z.number(), z.number(), z.number(), z.number()]).optional(),
73+
minzoom: z.number().min(0).max(22).optional(),
74+
maxzoom: z.number().min(0).max(22).optional(),
75+
tileSize: z.number().optional(),
76+
attribution: z.string().optional(),
77+
encoding: z.enum(['terrarium', 'mapbox']).optional(),
78+
volatile: z.boolean().optional()
79+
});
80+
81+
const GeoJSONSourceSchema = z.object({
82+
type: z.literal('geojson'),
83+
data: z.union([z.string(), z.any()]), // URL or inline GeoJSON
84+
maxzoom: z.number().min(0).max(24).optional(),
85+
attribution: z.string().optional(),
86+
buffer: z.number().min(0).max(512).optional(),
87+
tolerance: z.number().optional(),
88+
cluster: z.boolean().optional(),
89+
clusterRadius: z.number().optional(),
90+
clusterMaxZoom: z.number().optional(),
91+
clusterProperties: z.record(z.any()).optional(),
92+
lineMetrics: z.boolean().optional(),
93+
generateId: z.boolean().optional(),
94+
promoteId: z.union([z.string(), z.record(z.string())]).optional()
95+
});
96+
97+
const ImageSourceSchema = z.object({
98+
type: z.literal('image'),
99+
url: z.string(),
100+
coordinates: z.tuple([
101+
CoordinatesSchema,
102+
CoordinatesSchema,
103+
CoordinatesSchema,
104+
CoordinatesSchema
105+
])
106+
});
107+
108+
const VideoSourceSchema = z.object({
109+
type: z.literal('video'),
110+
urls: z.array(z.string()),
111+
coordinates: z.tuple([
112+
CoordinatesSchema,
113+
CoordinatesSchema,
114+
CoordinatesSchema,
115+
CoordinatesSchema
116+
])
117+
});
118+
119+
const SourceSchema = z.union([
120+
VectorSourceSchema,
121+
RasterSourceSchema,
122+
RasterDemSourceSchema,
123+
GeoJSONSourceSchema,
124+
ImageSourceSchema,
125+
VideoSourceSchema
126+
]);
127+
128+
// Layer schema (simplified - full schema would be very extensive)
129+
const LayerSchema = z.object({
130+
id: z.string().describe('Unique layer name'),
131+
type: z.enum([
132+
'fill',
133+
'line',
134+
'symbol',
135+
'circle',
136+
'heatmap',
137+
'fill-extrusion',
138+
'raster',
139+
'hillshade',
140+
'background',
141+
'sky',
142+
'slot',
143+
'clip',
144+
'model',
145+
'raster-particle',
146+
'building'
147+
]),
148+
source: z
149+
.string()
150+
.optional()
151+
.describe('Source name (not required for background/sky/slot)'),
152+
'source-layer': z
153+
.string()
154+
.optional()
155+
.describe('Layer from vector tile source'),
156+
minzoom: z.number().min(0).max(24).optional(),
157+
maxzoom: z.number().min(0).max(24).optional(),
158+
filter: z.any().optional().describe('Expression for filtering features'),
159+
layout: z.record(z.any()).optional(),
160+
paint: z.record(z.any()).optional(),
161+
metadata: z.record(z.any()).optional(),
162+
slot: z.string().optional().describe('Slot this layer is assigned to')
163+
});
164+
165+
// Style import schema
166+
const StyleImportSchema = z.object({
167+
id: z.string(),
168+
url: z.string(),
169+
config: z.record(z.any()).optional()
170+
});
171+
172+
// Base Style properties (shared between input and output)
173+
export const BaseStylePropertiesSchema = z.object({
174+
// Required Style Spec properties
175+
version: z
176+
.literal(8)
177+
.describe('Style specification version number. Must be 8'),
178+
sources: z.record(SourceSchema).describe('Data source specifications'),
179+
layers: z.array(LayerSchema).describe('Layers in draw order'),
180+
181+
// Optional Style Spec properties
182+
metadata: z
183+
.record(z.any())
184+
.optional()
185+
.describe('Arbitrary properties for tracking'),
186+
center: CoordinatesSchema.optional().describe(
187+
'Default map center [longitude, latitude]'
188+
),
189+
zoom: z.number().optional().describe('Default zoom level'),
190+
bearing: z.number().optional().describe('Default bearing in degrees'),
191+
pitch: z.number().optional().describe('Default pitch in degrees'),
192+
sprite: z
193+
.string()
194+
.optional()
195+
.describe('Base URL for sprite image and metadata'),
196+
glyphs: z.string().optional().describe('URL template for glyph sets'),
197+
light: LightSchema.optional()
198+
.nullable()
199+
.describe('Global light source (deprecated, use lights)'),
200+
lights: LightsSchema.optional()
201+
.nullable()
202+
.describe('Array of 3D light sources'),
203+
terrain: TerrainSchema.optional()
204+
.nullable()
205+
.describe('Global terrain elevation'),
206+
fog: z.record(z.any()).optional().nullable().describe('Fog properties'),
207+
projection: z
208+
.record(z.any())
209+
.optional()
210+
.nullable()
211+
.describe('Map projection'),
212+
transition: TransitionSchema.optional()
213+
.nullable()
214+
.describe('Default transition timing'),
215+
imports: z
216+
.array(StyleImportSchema)
217+
.optional()
218+
.nullable()
219+
.describe('Imported styles')
220+
});
221+
222+
export type MapboxSource = z.infer<typeof SourceSchema>;
223+
export type MapboxLayer = z.infer<typeof LayerSchema>;

0 commit comments

Comments
 (0)