Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
## Unreleased

### New Features

- **`preview_style_tool` and `style_comparison_tool` no longer require an existing `accessToken`.** Both previously made `accessToken` a required `pk.*` input — meaning a caller had to already have (or separately go create) a public token before either tool would do anything, for even a quick one-off preview. `accessToken` is now optional on both: when omitted, the tool auto-generates a preview token from the server's own access token (the same pattern `geojson_preview_tool`'s resource already used) via a new shared `mintScopedPreviewToken` utility, so a first call needs no setup at all.
- Pass `share: true` alongside your own `accessToken` on either tool to get a link built from a token you manage yourself, for when you actually want something durable to bookmark or hand to someone else — `share: true` without an `accessToken` is a clear validation error, not a silent fallback.
- The two tools' auto-mint tokens differ in shape, confirmed live against the real API: `preview_style_tool` mints a short-lived (~1h) `tk.*` token, since the Styles API's embeddable HTML preview page and GL JS both accept it fine. `style_comparison_tool` mints a non-expiring `pk.*` token instead — `agent.mapbox.com/tools/style-compare`, which its comparison link embeds, validates the token prefix itself and hard-rejects anything but `pk.*` (a `tk.*` token 400s there with "Configuration Error: Invalid token type"). The `pk.*` token is still narrowly scoped (`styles:tiles`/`styles:read`/`fonts:read`) and auto-generated, just not self-expiring; it persists on the account until manually revoked.
- Both tools now take `httpRequest` as a constructor dependency (matching every other network-calling tool in this repo) to make the mint call.
- **Hosted-endpoint-aware error messages.** Per `README.md`, the hosted MCP endpoint authenticates with its own access token rather than a personal Mapbox account token, and that token isn't granted `tokens:write` — so auto-mint can't work there. Without this, a hosted caller who omits `accessToken` would have hit a raw, misleading `jwtUtils` error (`"MAPBOX_ACCESS_TOKEN is not in valid JWT format"`, referencing an env var the hosted deployment doesn't even use) or a bare `Token API 403`. A new `describeAutoMintFailure` helper rewrites both into an actionable message pointing at `accessToken`/`list_tokens_tool`/`create_token_tool` instead.

### Breaking Changes

- **Consolidated `GeojsonPreviewUIResource` and `PreviewStyleUIResource` into a single `MapPreviewUIResource`.** Both were near-identical hand-written MCP Apps templates — the same postMessage handshake, fullscreen/open-link controls, and resize handling copy-pasted across ~650 lines, differing only in what they drew on the map once a tool result arrived (a GeoJSON overlay on the default Standard style vs. swapping to an arbitrary preview style). `geojson_preview_tool` and `preview_style_tool` now both declare `_meta.ui.resourceUri: 'ui://mapbox/map-preview/index.html'`, served by the merged resource, which dispatches on the shape of the tool-result URL it receives (a `geojson.io` URL vs. a Styles API `.html?access_token=...` preview URL) rather than assuming a fixed mode. Neither tool's own input/output contract changed.
- The public resource exports change: `previewStyleUI`/`geojsonPreviewUI` (from `@mapbox/mcp-devkit-server/resources`) are replaced by a single `mapPreviewUI`. `GeojsonPreviewUIResource`/`PreviewStyleUIResource` class exports are removed in favor of `MapPreviewUIResource`.
- `style_comparison_tool`'s `StyleComparisonUIResource` is untouched and stays separate — it renders two synced `mapboxgl.Map` instances under a swipe/compare slider, a genuinely different UI shape from "one map, different content," not just another mode to fold in.
- The GeoJSON-preview path keeps its existing eager map bootstrap (drawing the default Standard style immediately, before any tool result arrives, so an overlay has something to render onto right away); the style-preview path now reuses that same map instance via `setStyle()` when it exists, falling back to constructing its own (as before) when it doesn't. Verified live against the real Mapbox API in a real browser: the GeoJSON overlay path and the style-swap-in-place path (loading a real custom style by name) both work end-to-end on the merged resource.

### Dependencies

- Bumped `@modelcontextprotocol/sdk` to `1.30.0`. Not adopting the `2026-07-28` spec revision this release covers (stateless request/response model, elicitation replaced by Multi Round-Trip Requests, Sampling deprecated) — that's a separate migration, tracked in #130, given this repo's own elicitation-based features depend on the mechanism being replaced. Regenerated `patches/@modelcontextprotocol+sdk+1.30.0.patch` (previously pinned to `1.29.0`) — same patch content, applies cleanly to the new version, verified live against the built server.
Expand Down
16 changes: 7 additions & 9 deletions src/resources/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,16 @@ export { MapboxStyleLayersResource } from './mapbox-style-layers-resource/Mapbox
export { MapboxStreetsV8FieldsResource } from './mapbox-streets-v8-fields-resource/MapboxStreetsV8FieldsResource.js';
export { MapboxTokenScopesResource } from './mapbox-token-scopes-resource/MapboxTokenScopesResource.js';
export { MapboxLayerTypeMappingResource } from './mapbox-layer-type-mapping-resource/MapboxLayerTypeMappingResource.js';
export { PreviewStyleUIResource } from './ui-apps/PreviewStyleUIResource.js';
export { MapPreviewUIResource } from './ui-apps/MapPreviewUIResource.js';
export { StyleComparisonUIResource } from './ui-apps/StyleComparisonUIResource.js';
export { GeojsonPreviewUIResource } from './ui-apps/GeojsonPreviewUIResource.js';

// Import resource classes for instantiation
import { MapboxStyleLayersResource } from './mapbox-style-layers-resource/MapboxStyleLayersResource.js';
import { MapboxStreetsV8FieldsResource } from './mapbox-streets-v8-fields-resource/MapboxStreetsV8FieldsResource.js';
import { MapboxTokenScopesResource } from './mapbox-token-scopes-resource/MapboxTokenScopesResource.js';
import { MapboxLayerTypeMappingResource } from './mapbox-layer-type-mapping-resource/MapboxLayerTypeMappingResource.js';
import { PreviewStyleUIResource } from './ui-apps/PreviewStyleUIResource.js';
import { MapPreviewUIResource } from './ui-apps/MapPreviewUIResource.js';
import { StyleComparisonUIResource } from './ui-apps/StyleComparisonUIResource.js';
import { GeojsonPreviewUIResource } from './ui-apps/GeojsonPreviewUIResource.js';

// Export pre-configured resource instances with short, clean names

Expand All @@ -50,15 +48,15 @@ export const mapboxTokenScopes = new MapboxTokenScopesResource();
/** Mapbox layer type mapping reference */
export const mapboxLayerTypeMapping = new MapboxLayerTypeMappingResource();

/** Preview style UI resource */
export const previewStyleUI = new PreviewStyleUIResource();
/**
* Shared map preview UI resource — serves both geojson_preview_tool and
* preview_style_tool's inline MCP Apps preview.
*/
export const mapPreviewUI = new MapPreviewUIResource();

/** Style comparison UI resource */
export const styleComparisonUI = new StyleComparisonUIResource();

/** GeoJSON preview UI resource */
export const geojsonPreviewUI = new GeojsonPreviewUIResource();

// Export registry functions for batch access
export {
getAllResources,
Expand Down
8 changes: 3 additions & 5 deletions src/resources/resourceRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ import { MapboxStyleLayersResource } from './mapbox-style-layers-resource/Mapbox
import { MapboxStreetsV8FieldsResource } from './mapbox-streets-v8-fields-resource/MapboxStreetsV8FieldsResource.js';
import { MapboxTokenScopesResource } from './mapbox-token-scopes-resource/MapboxTokenScopesResource.js';
import { MapboxLayerTypeMappingResource } from './mapbox-layer-type-mapping-resource/MapboxLayerTypeMappingResource.js';
import { PreviewStyleUIResource } from './ui-apps/PreviewStyleUIResource.js';
import { MapPreviewUIResource } from './ui-apps/MapPreviewUIResource.js';
import { StyleComparisonUIResource } from './ui-apps/StyleComparisonUIResource.js';
import { GeojsonPreviewUIResource } from './ui-apps/GeojsonPreviewUIResource.js';

// Central registry of all resources
export const ALL_RESOURCES = [
Expand All @@ -16,9 +15,8 @@ export const ALL_RESOURCES = [
new MapboxTokenScopesResource(),
new MapboxLayerTypeMappingResource(),
// MCP Apps UI resources (ui:// scheme)
new PreviewStyleUIResource(),
new StyleComparisonUIResource(),
new GeojsonPreviewUIResource()
new MapPreviewUIResource(),
new StyleComparisonUIResource()
] as const;

export type ResourceInstance = (typeof ALL_RESOURCES)[number];
Expand Down
Loading
Loading