diff --git a/README.md b/README.md index d80fa40..5ac5456 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ https://github.com/user-attachments/assets/8b1b8ef2-9fba-4951-bc9a-beaed4f6aff6 - [Creating New Tools](#creating-new-tools) - [Environment Variables](#environment-variables) - [VERBOSE_ERRORS](#verbose_errors) + - [Troubleshooting](#troubleshooting) - [Contributing](#contributing) ## Quick Start @@ -558,6 +559,16 @@ Set `VERBOSE_ERRORS=true` to get detailed error messages from the MCP server. Th By default, the server returns generic error messages. With verbose errors enabled, you'll receive the actual error details, which can help diagnose API connection issues, invalid parameters, or other problems. +## Troubleshooting + +**Issue:** Tools fail with authentication errors + +**Solution:** Check that your `MAPBOX_ACCESS_TOKEN` has the required scopes for the tool you're using. See the token scopes section above. + +**Issue:** Large GeoJSON files cause slow performance + +**Solution:** The GeoJSON preview tool may be slow with very large files. Consider simplifying geometries or using smaller datasets for preview purposes. + ## Contributing We welcome contributions to the Mapbox Development MCP Server! Please review our standards and guidelines before contributing: diff --git a/src/tools/create-style-tool/CreateStyleTool.input.schema.ts b/src/tools/create-style-tool/CreateStyleTool.input.schema.ts index dd5c8b7..a20c5f2 100644 --- a/src/tools/create-style-tool/CreateStyleTool.input.schema.ts +++ b/src/tools/create-style-tool/CreateStyleTool.input.schema.ts @@ -3,30 +3,17 @@ import { z } from 'zod'; -// INPUT Schema - Simplified schema for creating styles -// Only defines the essential required fields. Additional Mapbox Style Specification -// properties (sources, layers, sprite, glyphs, etc.) are allowed via .passthrough() +// INPUT Schema - Accepts a complete Mapbox Style Specification as a generic object +// This avoids complex schemas with .passthrough() that break some MCP clients (Cursor + OpenAI) // Full spec: https://docs.mapbox.com/mapbox-gl-js/style-spec/ -export const MapboxStyleInputSchema = z - .object({ - name: z.string().describe('Human-readable name for the style (REQUIRED)'), - version: z - .literal(8) - .describe('Style specification version number. Must be 8'), - // Note: The Mapbox API requires at minimum 'version', 'name', 'sources', and 'layers'. - // We only validate 'name' and 'version' here. Other fields like sources, layers, sprite, - // glyphs, center, zoom, etc. are passed through without explicit validation to avoid - // overwhelming clients with the full 18+ field schema. - sources: z - .record(z.any()) - .optional() - .describe('Data source specifications'), - layers: z.array(z.any()).optional().describe('Layers in draw order') - }) - .passthrough() - .describe( - 'Mapbox style input. Accepts standard Mapbox Style Specification properties. Only key fields are validated; additional properties (center, zoom, bearing, pitch, sprite, glyphs, metadata, etc.) are accepted but not explicitly defined to keep schema manageable.' - ); +export const CreateStyleInputSchema = z.object({ + name: z.string().describe('Human-readable name for the style'), + style: z + .record(z.any()) + .describe( + 'Complete Mapbox Style Specification object. Must include: version (8), sources, layers. Optional: sprite, glyphs, center, zoom, bearing, pitch, metadata, etc. See https://docs.mapbox.com/mapbox-gl-js/style-spec/' + ) +}); // Type exports -export type MapboxStyleInput = z.infer; +export type CreateStyleInput = z.infer; diff --git a/src/tools/create-style-tool/CreateStyleTool.ts b/src/tools/create-style-tool/CreateStyleTool.ts index edf0f90..7e6ecf7 100644 --- a/src/tools/create-style-tool/CreateStyleTool.ts +++ b/src/tools/create-style-tool/CreateStyleTool.ts @@ -7,8 +7,8 @@ import { getUserNameFromToken } from '../../utils/jwtUtils.js'; import { filterExpandedMapboxStyles } from '../../utils/styleUtils.js'; import { MapboxApiBasedTool } from '../MapboxApiBasedTool.js'; import { - MapboxStyleInputSchema, - MapboxStyleInput + CreateStyleInputSchema, + CreateStyleInput } from './CreateStyleTool.input.schema.js'; import { MapboxStyleOutput, @@ -16,7 +16,7 @@ import { } from './CreateStyleTool.output.schema.js'; export class CreateStyleTool extends MapboxApiBasedTool< - typeof MapboxStyleInputSchema, + typeof CreateStyleInputSchema, typeof MapboxStyleOutputSchema > { name = 'create_style_tool'; @@ -31,25 +31,31 @@ export class CreateStyleTool extends MapboxApiBasedTool< constructor(params: { httpRequest: HttpRequest }) { super({ - inputSchema: MapboxStyleInputSchema, + inputSchema: CreateStyleInputSchema, outputSchema: MapboxStyleOutputSchema, httpRequest: params.httpRequest }); } protected async execute( - input: MapboxStyleInput, + input: CreateStyleInput, accessToken?: string ): Promise { const username = getUserNameFromToken(accessToken); const url = `${MapboxApiBasedTool.mapboxApiEndpoint}styles/v1/${username}?access_token=${accessToken}`; + // Merge name into style object for API request + const payload = { + ...input.style, + name: input.name + }; + const response = await this.httpRequest(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(input) + body: JSON.stringify(payload) }); if (!response.ok) { diff --git a/src/tools/update-style-tool/UpdateStyleTool.input.schema.ts b/src/tools/update-style-tool/UpdateStyleTool.input.schema.ts index c16c385..ef1dcbf 100644 --- a/src/tools/update-style-tool/UpdateStyleTool.input.schema.ts +++ b/src/tools/update-style-tool/UpdateStyleTool.input.schema.ts @@ -3,29 +3,17 @@ import { z } from 'zod'; -// Simplified Mapbox Style Input Schema for updates -// Only defines essential fields. Additional properties are accepted via .passthrough() -export const MapboxStyleInputSchema = z - .object({ - name: z.string().optional().describe('Human-readable name for the style'), - version: z.literal(8).optional().describe('Style specification version'), - sources: z - .record(z.any()) - .optional() - .describe('Data source specifications'), - layers: z.array(z.any()).optional().describe('Layers in draw order') - }) - .passthrough() - .describe( - 'Mapbox style properties to update. Accepts standard Mapbox Style Specification properties.' - ); - +// INPUT Schema - Accepts a complete Mapbox Style Specification as a generic object +// This avoids complex schemas with .passthrough() that break some MCP clients (Cursor + OpenAI) export const UpdateStyleInputSchema = z.object({ styleId: z.string().describe('Style ID to update'), name: z.string().optional().describe('New name for the style'), - style: MapboxStyleInputSchema.optional().describe( - 'Updated Mapbox style specification object' - ) + style: z + .record(z.any()) + .optional() + .describe( + 'Complete Mapbox Style Specification object to update. Must include: version (8), sources, layers. Optional: sprite, glyphs, center, zoom, bearing, pitch, metadata, etc. See https://docs.mapbox.com/mapbox-gl-js/style-spec/' + ) }); export type UpdateStyleInput = z.infer; diff --git a/test/tools/create-style-tool/CreateStyleTool.test.ts b/test/tools/create-style-tool/CreateStyleTool.test.ts index 79df03d..341e3d1 100644 --- a/test/tools/create-style-tool/CreateStyleTool.test.ts +++ b/test/tools/create-style-tool/CreateStyleTool.test.ts @@ -29,10 +29,10 @@ describe('CreateStyleTool', () => { }); it('should have correct input schema', async () => { - const { MapboxStyleInputSchema } = await import( + const { CreateStyleInputSchema } = await import( '../../../src/tools/create-style-tool/CreateStyleTool.input.schema.js' ); - expect(MapboxStyleInputSchema).toBeDefined(); + expect(CreateStyleInputSchema).toBeDefined(); }); }); @@ -50,9 +50,11 @@ describe('CreateStyleTool', () => { await new CreateStyleTool({ httpRequest }).run({ name: 'Test Style', - version: 8, - sources: {}, - layers: [] + style: { + version: 8, + sources: {}, + layers: [] + } }); assertHeadersSent(mockHttpRequest); }); @@ -66,9 +68,11 @@ describe('CreateStyleTool', () => { const result = await new CreateStyleTool({ httpRequest }).run({ name: 'Test Style', - version: 8, - sources: {}, - layers: [] + style: { + version: 8, + sources: {}, + layers: [] + } }); expect(result.isError).toBe(true); diff --git a/test/tools/update-style-tool/UpdateStyleTool.test.ts b/test/tools/update-style-tool/UpdateStyleTool.test.ts index 987815e..1f59c20 100644 --- a/test/tools/update-style-tool/UpdateStyleTool.test.ts +++ b/test/tools/update-style-tool/UpdateStyleTool.test.ts @@ -29,10 +29,10 @@ describe('UpdateStyleTool', () => { }); it('should have correct input schema', async () => { - const { MapboxStyleInputSchema } = await import( + const { UpdateStyleInputSchema } = await import( '../../../src/tools/update-style-tool/UpdateStyleTool.input.schema.js' ); - expect(MapboxStyleInputSchema).toBeDefined(); + expect(UpdateStyleInputSchema).toBeDefined(); }); });