Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
1e72d21
Add server-level icons with light and dark theme support
mattpodwysocki Jan 12, 2026
c205821
Update @modelcontextprotocol/sdk to 1.25.2
mattpodwysocki Jan 12, 2026
ca757a9
Merge branch 'main' of github.com:mapbox/mcp-server
mattpodwysocki Jan 13, 2026
dc3e501
Merge branch 'main' of github.com:mapbox/mcp-server
mattpodwysocki Jan 26, 2026
8f325eb
Merge branch 'main' of github.com:mapbox/mcp-server
mattpodwysocki Jan 27, 2026
5c160cc
Merge branch 'main' of github.com:mapbox/mcp-server
mattpodwysocki Jan 29, 2026
04a1930
Merge branch 'main' of github.com:mapbox/mcp-server
mattpodwysocki Feb 9, 2026
79ef57e
Merge branch 'main' of github.com:mapbox/mcp-server
mattpodwysocki Feb 16, 2026
9bde92c
Merge branch 'main' of github.com:mapbox/mcp-server
mattpodwysocki Feb 23, 2026
08f374d
Merge branch 'main' of github.com:mapbox/mcp-server
mattpodwysocki Feb 26, 2026
efd96fa
Merge branch 'main' of github.com:mapbox/mcp-server
mattpodwysocki Mar 4, 2026
2aba9b7
Merge branch 'main' of github.com:mapbox/mcp-server
mattpodwysocki Mar 6, 2026
cd1d797
Merge branch 'main' of github.com:mapbox/mcp-server
mattpodwysocki Apr 1, 2026
a9c8261
Merge branch 'main' of github.com:mapbox/mcp-server
mattpodwysocki Apr 1, 2026
188f51a
chore: add CVE-2026-4926 entry to CHANGELOG
mattpodwysocki Apr 1, 2026
a9653e2
Merge branch 'main' of github.com:mapbox/mcp-server
mattpodwysocki Apr 2, 2026
814f635
Merge branch 'main' of github.com:mapbox/mcp-server
mattpodwysocki Apr 13, 2026
42acbeb
Merge branch 'main' of github.com:mapbox/mcp-server
mattpodwysocki Apr 13, 2026
80a5750
Merge branch 'main' of github.com:mapbox/mcp-server
mattpodwysocki Apr 14, 2026
8490ef9
Merge branch 'main' of github.com:mapbox/mcp-server
mattpodwysocki May 27, 2026
c554cc9
feat: add directions_app_tool — interactive GLJS map as MCP App
mattpodwysocki May 27, 2026
a137f78
feat: directions_app_tool resolves public token via Tokens API
mattpodwysocki May 27, 2026
ae44881
refactor: directions_app_tool uses MCP Apps resource pattern
mattpodwysocki May 27, 2026
fb12b89
fix(directions_app): tighten camera padding so the route fills the vi…
mattpodwysocki May 27, 2026
f653375
fix(directions_app): defer fitBounds until after iframe resize
mattpodwysocki May 27, 2026
277d267
refactor: fold MCP App support into directions_tool (drops directions…
mattpodwysocki Jun 1, 2026
9fc4467
fix(directions_app): decode polyline geometries in the iframe
mattpodwysocki Jun 1, 2026
b8fffa2
fix(directions_app): read temp resource when geometry is offloaded
mattpodwysocki Jun 1, 2026
e8602f3
fix(directions_app): review feedback from PR #189
mattpodwysocki Jun 1, 2026
8681d0b
Merge branch 'main' into feat/directions-app-tool
mattpodwysocki Jun 1, 2026
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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@

### New Features

- **`directions_tool` now renders as a live Mapbox GL JS map** for both the MCP Apps spec and legacy MCP-UI clients:
- **MCP Apps**: the tool declares `_meta.ui.resourceUri` pointing to a new `DirectionsAppUIResource` (`ui://mapbox/directions-app/index.html`). MCP App–capable hosts (Claude Desktop, VS Code, Cursor) render the route via postMessage handoff.
- **MCP-UI**: when `geometries=geojson` is requested and the response carries a renderable LineString, an inline `rawHtml` UIResource is added to the tool's `content[]` (gated by the existing `ENABLE_MCP_UI`/`--disable-mcp-ui` flag, like `static_map_image_tool`).
- **One source of truth**: both pathways render the same HTML produced by `renderDirectionsAppHtml` — for MCP Apps the resource serves a generic version and the iframe receives the tool result via postMessage; for MCP-UI the tool bakes the route geometry into the HTML before returning. No more "GL JS map for one client, static image for the other."
- **Public token**: resolved server-side via `GET /tokens/v2/{user}?default=true` (requires `tokens:read` on the `sk.*` token) with `MAPBOX_PUBLIC_TOKEN` env var fallback. Non-MCP-App hosts that also have MCP-UI disabled ignore both UI hints and consume the existing text/structuredContent payload unchanged.
- **Graceful degradation**: responses without renderable geometry (>50KB temporary-resource path, `geometries=none`, `geometries=polyline*`) skip the inline rawHtml block and show a "no geometry to render" message in the MCP App iframe.
- **CSP**: `_meta.ui.csp.workerDomains: ['blob:']` so MCP App hosts grant Mapbox GL JS the iframe sandbox permissions it needs.
- **MCP Completions capability**: Add auto-completion support for prompt arguments per MCP spec (2025-11-25). Clients can now suggest values when users fill in prompt parameters (#176)
- `category` argument on `find-places-nearby` — 482 Mapbox Search API categories
- `mode` argument on `get-directions`, `search-along-route`, `show-reachable-areas` — driving, driving-traffic, walking, cycling
Expand Down
4 changes: 2 additions & 2 deletions docs/importing-tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ import {
centroid,
distance,
midpoint,
pointInPolygon,
pointsWithinPolygon,
simplify,

// API tools (HTTP pre-configured)
Expand Down Expand Up @@ -149,7 +149,7 @@ import {
CentroidTool,
DistanceTool,
MidpointTool,
PointInPolygonTool,
PointsWithinPolygonTool,
SimplifyTool,

// API tools
Expand Down
2 changes: 2 additions & 0 deletions src/resources/resourceRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import { CategoryListResource } from './category-list/CategoryListResource.js';
import { TemporaryDataResource } from './temporary/TemporaryDataResource.js';
import { StaticMapUIResource } from './ui-apps/StaticMapUIResource.js';
import { DirectionsAppUIResource } from './ui-apps/DirectionsAppUIResource.js';
import { VersionResource } from './version/VersionResource.js';
import { httpRequest } from '../utils/httpPipeline.js';

Expand All @@ -14,6 +15,7 @@ export const ALL_RESOURCES = [
new CategoryListResource({ httpRequest }),
new TemporaryDataResource(),
new StaticMapUIResource(),
new DirectionsAppUIResource({ httpRequest }),
new VersionResource()
] as const;

Expand Down
89 changes: 89 additions & 0 deletions src/resources/ui-apps/DirectionsAppUIResource.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Copyright (c) Mapbox, Inc.
// Licensed under the MIT License.

import type { RequestHandlerExtra } from '@modelcontextprotocol/sdk/shared/protocol.js';
import type {
ReadResourceResult,
ServerNotification,
ServerRequest
} from '@modelcontextprotocol/sdk/types.js';
import { RESOURCE_MIME_TYPE } from '@modelcontextprotocol/ext-apps/server';
import { BaseResource } from '../BaseResource.js';
import type { HttpRequest } from '../../utils/types.js';
import { resolveMapboxPublicToken } from '../../utils/mapboxPublicToken.js';
import { renderDirectionsAppHtml } from './directionsAppHtml.js';

/**
* MCP Apps resource for `directions_tool` — serves the HTML at
* `ui://mapbox/directions-app/index.html`. The iframe waits for the host to
* deliver the tool result via the `ui/notifications/tool-result` postMessage
* event and renders the route from `structuredContent.routes[0]`.
*
* The legacy MCP-UI pathway (inline `rawHtml` on the tool result) uses the
* same HTML template via `renderDirectionsAppHtml` with geometry baked in at
* tool-execute time.
*/
export class DirectionsAppUIResource extends BaseResource {
readonly name = 'Directions App UI';
readonly uri = 'ui://mapbox/directions-app/index.html';
readonly description =
'Interactive UI for visualizing a Mapbox directions route with Mapbox GL JS (MCP Apps)';
readonly mimeType = RESOURCE_MIME_TYPE;

private readonly httpRequest: HttpRequest;
private readonly apiEndpoint: () => string;

constructor(params: {
httpRequest: HttpRequest;
apiEndpoint?: () => string;
}) {
super();
this.httpRequest = params.httpRequest;
this.apiEndpoint =
params.apiEndpoint ??
(() => process.env.MAPBOX_API_ENDPOINT || 'https://api.mapbox.com/');
}

async read(
_uri: string,
extra?: RequestHandlerExtra<ServerRequest, ServerNotification>
): Promise<ReadResourceResult> {
const accessToken =
(extra?.authInfo?.token as string | undefined) ||
process.env.MAPBOX_ACCESS_TOKEN ||
'';

const publicToken = await resolveMapboxPublicToken({
accessToken,
apiEndpoint: this.apiEndpoint(),
httpRequest: this.httpRequest
});

const html = renderDirectionsAppHtml({
publicToken: publicToken ?? ''
});

return {
contents: [
{
uri: this.uri,
mimeType: RESOURCE_MIME_TYPE,
text: html,
_meta: {
ui: {
csp: {
connectDomains: [
'https://*.mapbox.com',
'https://events.mapbox.com'
],
resourceDomains: ['https://api.mapbox.com'],
workerDomains: ['blob:']

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-read the PR description and saw you reference hosted-mcp-server's GeojsonPreviewUIResource as precedent — two questions:

  1. I checked @modelcontextprotocol/ext-apps@1.7.2 (latest) and workerDomains isn't in the McpUiResourceCsp interface — only connectDomains, resourceDomains, frameDomains, baseUriDomains are declared. Is the Mapbox host honoring workerDomains as a private extension, or is it being recognized some other way?

  2. The 'verify rendered map loads in Claude Desktop' manual check in your test plan is still unchecked. The unit test (DirectionsAppUIResource.test.ts:72) only asserts the field is present in the returned metadata, not that any host applies it. Since Mapbox GL JS won't initialize without worker-src blob:, would be good to confirm end-to-end before merge — if the spec doesn't have workerDomains, the map may be working in your test host for an unrelated reason (e.g. permissive default CSP).

},
preferredSize: { width: 1000, height: 600 }
}
}
}
]
};
}
}
Loading
Loading