diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ddf671..f1da222 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### Fixed +- **`create-and-preview-style` prompt now defaults to the Standard base style, not Classic `streets-v12`.** `StyleBuilderTool` (used by every other style-related prompt in this repo) has defaulted `base_style` to `"standard"` for a while — "ALWAYS use 'standard' as the default for all new styles" — but this prompt's own `base_style` fallback and its "Create the map style" step were never updated to match: it hardcoded `streets-v12` and hand-authored a bare Classic-style JSON skeleton (`sources`/`layers` background fill) directly in the prompt text, disconnected from the `base_style` argument entirely. Now defaults to `"standard"` and, like `build-custom-map` and other prompts in this repo, delegates style construction to `style_builder_tool` (which knows how to build either Standard or Classic structures correctly) instead of hand-rolling a Classic-only skeleton that would have been wrong for any base style other than the one it hardcoded. - **Startup logging messages (`.env` status, tracing status, detected client capabilities) now actually reach clients.** The `McpServer` never declared the `logging` capability, so every `sendLoggingMessage` call was a silent no-op regardless of when it was sent. Several of those calls also ran before `server.connect(transport)`, which would have dropped them anyway even with the capability declared, since there's no connected client yet to receive a notification sent before the transport is connected. Fixed both: `logging: {}` is now declared in the server's capabilities, and startup logging is deferred until after `connect()`. Covered by a new integration test that spawns the real built server and asserts a real client receives at least one startup log message. - **The server now identifies which MCP client connected to it, and fixes a related capability-read race.** `server.server.getClientVersion()`/`getClientCapabilities()` are only populated once the client's `initialize` request has been processed, which is not guaranteed by the time `server.connect()`'s promise resolves (it only waits for the transport to start). Reading them right after `connect()`, as the existing capability-gated tool registration did, reliably saw them as unset — confirmed live, even for a client that explicitly declared `elicitation` support. Both reads now happen inside a `server.server.oninitialized` callback, which only fires once the handshake is fully done. As part of this, the client's identity (name/version from its `initialize` request) is now logged on connect (e.g. `Client identified as: claude-ai v1.0.0`) and recorded as `mcp.client.name`/`mcp.client.version` on every subsequent tool-execution trace span, so OTel-backed traces can be filtered or grouped by client. diff --git a/src/prompts/CreateAndPreviewStylePrompt.ts b/src/prompts/CreateAndPreviewStylePrompt.ts index bb7d9ba..4a45eac 100644 --- a/src/prompts/CreateAndPreviewStylePrompt.ts +++ b/src/prompts/CreateAndPreviewStylePrompt.ts @@ -10,8 +10,9 @@ import { BasePrompt, type PromptArgument } from './BasePrompt.js'; * This prompt orchestrates multiple tools to: * 1. Check for an existing public token with styles:read scope * 2. Create a new public token if needed - * 3. Create the map style - * 4. Generate a preview link using the public token + * 3. Build the style specification (style_builder_tool, defaulting to the Standard base style) + * 4. Create the map style (create_style_tool) + * 5. Generate a preview link using the public token */ export class CreateAndPreviewStylePrompt extends BasePrompt { readonly name = 'create-and-preview-style'; @@ -32,7 +33,7 @@ export class CreateAndPreviewStylePrompt extends BasePrompt { { name: 'base_style', description: - 'Optional base style to start from (e.g., "streets-v12", "outdoors-v12", "light-v11", "dark-v11")', + 'Optional base style to start from. Defaults to "standard" (Mapbox\'s modern default). Only use a Classic style (e.g., "streets-v12", "outdoors-v12", "light-v11", "dark-v11") if explicitly requested.', required: false }, { @@ -51,7 +52,7 @@ export class CreateAndPreviewStylePrompt extends BasePrompt { getMessages(args: Record): PromptMessage[] { const styleName = args['style_name']; const styleDescription = args['style_description']; - const baseStyle = args['base_style'] || 'streets-v12'; + const baseStyle = args['base_style'] || 'standard'; const previewLocation = args['preview_location']; const previewZoom = args['preview_zoom'] || '12'; @@ -71,38 +72,26 @@ Follow these steps carefully: * scopes: ["styles:read"] - Save the token value from the response -3. **Create the map style** - - Use the create_style_tool to create the new style - - Style name: "${styleName}"`; +3. **Build the map style** + - Use the style_builder_tool to generate the style specification + - style_name: "${styleName}" + - base_style: "${baseStyle}"`; if (styleDescription) { - instructionText += `\n - Description: "${styleDescription}"`; + instructionText += `\n - Interpret this description into appropriate \`layers\`/\`global_settings\` entries: "${styleDescription}". If there's nothing specific to customize, pass an empty \`layers\` array to use ${baseStyle} as-is.`; + } else { + instructionText += `\n - No specific customizations requested — pass an empty \`layers\` array to use ${baseStyle} as-is.`; } - instructionText += `\n - Base the style on Mapbox ${baseStyle} - - You can start with a basic style like: - \`\`\`json - { - "version": 8, - "name": "${styleName}", - "sources": { - "mapbox": { - "type": "vector", - "url": "mapbox://mapbox.mapbox-streets-v8" - } - }, - "layers": [ - { - "id": "background", - "type": "background", - "paint": { "background-color": "#f0f0f0" } - } - ] - } - \`\`\` + instructionText += `\n - The tool returns a complete Mapbox GL JS style specification + +4. **Create the map style** + - Use the create_style_tool to save the generated style to the Mapbox account + - Style name: "${styleName}" + - Include the complete style specification from step 3 - Save the style ID from the response -4. **Generate preview link** +5. **Generate preview link** - Use the preview_style_tool with the style ID you just created`; if (previewLocation) { @@ -112,16 +101,16 @@ Follow these steps carefully: instructionText += `\n - Set zoom level to: ${previewZoom} - The tool will automatically use the public token you created/found earlier -5. **Validate the style** +6. **Validate the style** - Automatically run validation using the prepare-style-for-production prompt - - Pass the style ID from step 3 as the style_id_or_json parameter + - Pass the style ID from step 4 as the style_id_or_json parameter - This checks: * Expression syntax and correctness * Color contrast for accessibility (WCAG AA) * Style optimization opportunities - Validation is fast (offline processing only) -6. **Present complete results** +7. **Present complete results** - Show the user: * The created style ID * The preview URL (they can click to open in browser) diff --git a/test/prompts/CreateAndPreviewStylePrompt.test.ts b/test/prompts/CreateAndPreviewStylePrompt.test.ts index 900c72c..924a7d6 100644 --- a/test/prompts/CreateAndPreviewStylePrompt.test.ts +++ b/test/prompts/CreateAndPreviewStylePrompt.test.ts @@ -51,6 +51,25 @@ describe('CreateAndPreviewStylePrompt', () => { expect(text).toContain('preview_style_tool'); }); + it('defaults base_style to "standard", not the Classic "streets-v12"', () => { + const result = prompt.execute({ style_name: 'Test Style' }); + const text = result.messages[0].content.text; + + expect(text).toContain('base_style: "standard"'); + expect(text).not.toContain('streets-v12'); + expect(text).toContain('style_builder_tool'); + }); + + it('respects an explicit Classic base_style override', () => { + const result = prompt.execute({ + style_name: 'Test Style', + base_style: 'streets-v12' + }); + const text = result.messages[0].content.text; + + expect(text).toContain('base_style: "streets-v12"'); + }); + it('should include optional arguments in messages', () => { const result = prompt.execute({ style_name: 'Test Style',