Skip to content

Commit ba1813a

Browse files
[cursor] Adding schema fixes for known GPT/Cursor issues
1 parent 992585f commit ba1813a

File tree

8 files changed

+45
-165
lines changed

8 files changed

+45
-165
lines changed

CLAUDE.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ This file provides Claude and developers with essential context, commands, and s
7171

7272
## Known Issues & Warnings
7373

74-
- **Cursor + OpenAI models compatibility issue** - ALL OpenAI models (GPT-4, GPT-3.5, o1, o1-mini) fail with `[invalid_argument]` errors in Cursor when using `create_style_tool` and `update_style_tool` (works fine in VS Code, works fine with Claude in Cursor). Root cause: Cursor can't handle tools with complex input schemas when used with OpenAI models. **Workaround:** Set `CURSOR_OPENAI_MODE=true` to auto-disable the problematic tools. You'll still have 15/17 tools working.
7574
- Large GeoJSON files may cause slow performance in preview tools
7675
- Always check token scopes if a tool fails with authentication errors
7776
- Use `VERBOSE_ERRORS=true` for detailed error output

README.md

Lines changed: 0 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,7 @@ https://github.com/user-attachments/assets/8b1b8ef2-9fba-4951-bc9a-beaed4f6aff6
3535
- [Creating New Tools](#creating-new-tools)
3636
- [Environment Variables](#environment-variables)
3737
- [VERBOSE_ERRORS](#verbose_errors)
38-
- [CURSOR_OPENAI_MODE](#cursor_openai_mode)
3938
- [Troubleshooting](#troubleshooting)
40-
- [Cursor + OpenAI Models Issues](#cursor--openai-models-issues)
41-
- [General Troubleshooting](#general-troubleshooting)
4239
- [Contributing](#contributing)
4340

4441
## Quick Start
@@ -562,101 +559,8 @@ Set `VERBOSE_ERRORS=true` to get detailed error messages from the MCP server. Th
562559

563560
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.
564561

565-
#### CURSOR_OPENAI_MODE
566-
567-
Set `CURSOR_OPENAI_MODE=true` when using **any OpenAI model (GPT-4, GPT-3.5, o1, o1-mini) in Cursor**. This is a simple workaround for Cursor's bug with OpenAI models and complex tool schemas.
568-
569-
**What it does:**
570-
571-
- Automatically disables `create_style_tool` and `update_style_tool`
572-
- These tools have complex input schemas that break Cursor's OpenAI integration
573-
- You'll still have 15 out of 17 tools working (all read/query/preview operations)
574-
575-
**When to use:**
576-
577-
- ✅ Using GPT-4, GPT-3.5, o1, or o1-mini in Cursor
578-
- ❌ Not needed for Claude models in Cursor (all tools work)
579-
- ❌ Not needed in VS Code (all tools work with all models)
580-
581-
**Example:**
582-
583-
```json
584-
{
585-
"mcpServers": {
586-
"mapbox-devkit": {
587-
"env": {
588-
"MAPBOX_ACCESS_TOKEN": "your-token",
589-
"CURSOR_OPENAI_MODE": "true"
590-
}
591-
}
592-
}
593-
}
594-
```
595-
596562
## Troubleshooting
597563

598-
### Cursor + OpenAI Models Issues
599-
600-
**Problem:** When using **any OpenAI model (GPT-4, GPT-3.5, o1, o1-mini)** in Cursor, the `create_style_tool` and `update_style_tool` cause failures with `[invalid_argument]` errors.
601-
602-
**Example error:**
603-
604-
```
605-
ConnectError: [invalid_argument] Error
606-
The model returned an error. Try disabling MCP servers, or switch models.
607-
```
608-
609-
**Cause:** This is a Cursor-specific bug with o1 model MCP integration. The same server works fine with o1 in VS Code and other MCP clients.
610-
611-
**Root Cause:** Cursor's integration with OpenAI models fails when tools have complex input schemas with `.passthrough()` (like `create_style_tool` and `update_style_tool` which accept full Mapbox Style Specification objects). The error is: `[AiService] streamResponse ConnectError: [invalid_argument]`
612-
613-
**Affected:**
614-
615-
- ❌ Cursor + GPT-4 - Fails with these 2 tools
616-
- ❌ Cursor + GPT-3.5 - Fails with these 2 tools
617-
- ❌ Cursor + o1/o1-mini - Fails with these 2 tools
618-
- ✅ Cursor + Claude - Works with all tools
619-
- ✅ VS Code + any model - Works with all tools
620-
621-
**Simple Fix - Use CURSOR_OPENAI_MODE:**
622-
Add `CURSOR_OPENAI_MODE=true` to automatically disable the problematic tools:
623-
624-
```json
625-
{
626-
"mcpServers": {
627-
"mapbox-devkit": {
628-
"command": "node",
629-
"args": ["/path/to/dist/esm/index.js"],
630-
"env": {
631-
"MAPBOX_ACCESS_TOKEN": "your-token",
632-
"CURSOR_OPENAI_MODE": "true"
633-
}
634-
}
635-
}
636-
}
637-
```
638-
639-
This automatically disables `create_style_tool` and `update_style_tool` which have complex input schemas that break Cursor's OpenAI integration. You'll still have **15 out of 17 tools** working, including all read/query operations.
640-
641-
**Other Solutions:**
642-
643-
1. **Use Claude in Cursor** - All 17 tools work perfectly with Claude models in Cursor
644-
2. **Use VS Code** - All OpenAI models work with all 17 tools in VS Code (no workaround needed)
645-
3. **Manually disable tools:**
646-
```json
647-
{
648-
"args": [
649-
"/path/to/dist/esm/index.js",
650-
"--disable-tools",
651-
"create_style_tool,update_style_tool"
652-
]
653-
}
654-
```
655-
656-
**Status:** This is a Cursor bug with how it handles OpenAI models + MCP tools with complex input schemas. The same tools work fine in VS Code.
657-
658-
### General Troubleshooting
659-
660564
**Issue:** Tools fail with authentication errors
661565

662566
**Solution:** Check that your `MAPBOX_ACCESS_TOKEN` has the required scopes for the tool you're using. See the token scopes section above.

src/index.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,6 @@ const config = parseToolConfigFromArgs();
1616

1717
// Get and filter tools based on configuration
1818
const allTools = getAllTools();
19-
20-
// Cursor + OpenAI models have issues with complex input schemas (create_style_tool, update_style_tool)
21-
// This provides an easy workaround
22-
const cursorOpenAiMode = process.env.CURSOR_OPENAI_MODE === 'true';
23-
if (cursorOpenAiMode && !config.disabledTools) {
24-
config.disabledTools = ['create_style_tool', 'update_style_tool'];
25-
}
26-
2719
const enabledTools = filterTools(allTools, config);
2820

2921
// Create an MCP server

src/tools/create-style-tool/CreateStyleTool.input.schema.ts

Lines changed: 11 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,17 @@
33

44
import { z } from 'zod';
55

6-
// INPUT Schema - Simplified schema for creating styles
7-
// Only defines the essential required fields. Additional Mapbox Style Specification
8-
// properties (sources, layers, sprite, glyphs, etc.) are allowed via .passthrough()
6+
// INPUT Schema - Accepts a complete Mapbox Style Specification as a generic object
7+
// This avoids complex schemas with .passthrough() that break some MCP clients (Cursor + OpenAI)
98
// Full spec: https://docs.mapbox.com/mapbox-gl-js/style-spec/
10-
export const MapboxStyleInputSchema = z
11-
.object({
12-
name: z.string().describe('Human-readable name for the style (REQUIRED)'),
13-
version: z
14-
.literal(8)
15-
.describe('Style specification version number. Must be 8'),
16-
// Note: The Mapbox API requires at minimum 'version', 'name', 'sources', and 'layers'.
17-
// We only validate 'name' and 'version' here. Other fields like sources, layers, sprite,
18-
// glyphs, center, zoom, etc. are passed through without explicit validation to avoid
19-
// overwhelming clients with the full 18+ field schema.
20-
sources: z
21-
.record(z.any())
22-
.optional()
23-
.describe('Data source specifications'),
24-
layers: z.array(z.any()).optional().describe('Layers in draw order')
25-
})
26-
.passthrough()
27-
.describe(
28-
'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.'
29-
);
9+
export const CreateStyleInputSchema = z.object({
10+
name: z.string().describe('Human-readable name for the style'),
11+
style: z
12+
.record(z.any())
13+
.describe(
14+
'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/'
15+
)
16+
});
3017

3118
// Type exports
32-
export type MapboxStyleInput = z.infer<typeof MapboxStyleInputSchema>;
19+
export type CreateStyleInput = z.infer<typeof CreateStyleInputSchema>;

src/tools/create-style-tool/CreateStyleTool.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,16 @@ import { getUserNameFromToken } from '../../utils/jwtUtils.js';
77
import { filterExpandedMapboxStyles } from '../../utils/styleUtils.js';
88
import { MapboxApiBasedTool } from '../MapboxApiBasedTool.js';
99
import {
10-
MapboxStyleInputSchema,
11-
MapboxStyleInput
10+
CreateStyleInputSchema,
11+
CreateStyleInput
1212
} from './CreateStyleTool.input.schema.js';
1313
import {
1414
MapboxStyleOutput,
1515
MapboxStyleOutputSchema
1616
} from './CreateStyleTool.output.schema.js';
1717

1818
export class CreateStyleTool extends MapboxApiBasedTool<
19-
typeof MapboxStyleInputSchema,
19+
typeof CreateStyleInputSchema,
2020
typeof MapboxStyleOutputSchema
2121
> {
2222
name = 'create_style_tool';
@@ -31,25 +31,31 @@ export class CreateStyleTool extends MapboxApiBasedTool<
3131

3232
constructor(params: { httpRequest: HttpRequest }) {
3333
super({
34-
inputSchema: MapboxStyleInputSchema,
34+
inputSchema: CreateStyleInputSchema,
3535
outputSchema: MapboxStyleOutputSchema,
3636
httpRequest: params.httpRequest
3737
});
3838
}
3939

4040
protected async execute(
41-
input: MapboxStyleInput,
41+
input: CreateStyleInput,
4242
accessToken?: string
4343
): Promise<CallToolResult> {
4444
const username = getUserNameFromToken(accessToken);
4545
const url = `${MapboxApiBasedTool.mapboxApiEndpoint}styles/v1/${username}?access_token=${accessToken}`;
4646

47+
// Merge name into style object for API request
48+
const payload = {
49+
...input.style,
50+
name: input.name
51+
};
52+
4753
const response = await this.httpRequest(url, {
4854
method: 'POST',
4955
headers: {
5056
'Content-Type': 'application/json'
5157
},
52-
body: JSON.stringify(input)
58+
body: JSON.stringify(payload)
5359
});
5460

5561
if (!response.ok) {

src/tools/update-style-tool/UpdateStyleTool.input.schema.ts

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,17 @@
33

44
import { z } from 'zod';
55

6-
// Simplified Mapbox Style Input Schema for updates
7-
// Only defines essential fields. Additional properties are accepted via .passthrough()
8-
export const MapboxStyleInputSchema = z
9-
.object({
10-
name: z.string().optional().describe('Human-readable name for the style'),
11-
version: z.literal(8).optional().describe('Style specification version'),
12-
sources: z
13-
.record(z.any())
14-
.optional()
15-
.describe('Data source specifications'),
16-
layers: z.array(z.any()).optional().describe('Layers in draw order')
17-
})
18-
.passthrough()
19-
.describe(
20-
'Mapbox style properties to update. Accepts standard Mapbox Style Specification properties.'
21-
);
22-
6+
// INPUT Schema - Accepts a complete Mapbox Style Specification as a generic object
7+
// This avoids complex schemas with .passthrough() that break some MCP clients (Cursor + OpenAI)
238
export const UpdateStyleInputSchema = z.object({
249
styleId: z.string().describe('Style ID to update'),
2510
name: z.string().optional().describe('New name for the style'),
26-
style: MapboxStyleInputSchema.optional().describe(
27-
'Updated Mapbox style specification object'
28-
)
11+
style: z
12+
.record(z.any())
13+
.optional()
14+
.describe(
15+
'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/'
16+
)
2917
});
3018

3119
export type UpdateStyleInput = z.infer<typeof UpdateStyleInputSchema>;

test/tools/create-style-tool/CreateStyleTool.test.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ describe('CreateStyleTool', () => {
2929
});
3030

3131
it('should have correct input schema', async () => {
32-
const { MapboxStyleInputSchema } = await import(
32+
const { CreateStyleInputSchema } = await import(
3333
'../../../src/tools/create-style-tool/CreateStyleTool.input.schema.js'
3434
);
35-
expect(MapboxStyleInputSchema).toBeDefined();
35+
expect(CreateStyleInputSchema).toBeDefined();
3636
});
3737
});
3838

@@ -50,9 +50,11 @@ describe('CreateStyleTool', () => {
5050

5151
await new CreateStyleTool({ httpRequest }).run({
5252
name: 'Test Style',
53-
version: 8,
54-
sources: {},
55-
layers: []
53+
style: {
54+
version: 8,
55+
sources: {},
56+
layers: []
57+
}
5658
});
5759
assertHeadersSent(mockHttpRequest);
5860
});
@@ -66,9 +68,11 @@ describe('CreateStyleTool', () => {
6668

6769
const result = await new CreateStyleTool({ httpRequest }).run({
6870
name: 'Test Style',
69-
version: 8,
70-
sources: {},
71-
layers: []
71+
style: {
72+
version: 8,
73+
sources: {},
74+
layers: []
75+
}
7276
});
7377

7478
expect(result.isError).toBe(true);

test/tools/update-style-tool/UpdateStyleTool.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ describe('UpdateStyleTool', () => {
2929
});
3030

3131
it('should have correct input schema', async () => {
32-
const { MapboxStyleInputSchema } = await import(
32+
const { UpdateStyleInputSchema } = await import(
3333
'../../../src/tools/update-style-tool/UpdateStyleTool.input.schema.js'
3434
);
35-
expect(MapboxStyleInputSchema).toBeDefined();
35+
expect(UpdateStyleInputSchema).toBeDefined();
3636
});
3737
});
3838

0 commit comments

Comments
 (0)