Skip to content

Commit 83dff66

Browse files
Merge pull request #46 from mapbox/add-mcp-prompts
[prompts] Add MCP prompts for multi-step workflows
2 parents 1a7c843 + 942b30e commit 83dff66

18 files changed

+2626
-2
lines changed

CLAUDE.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,25 @@ The codebase organizes into:
1818
- `src/index.ts` - Main entry point with .env loading and server initialization
1919
- `src/config/toolConfig.ts` - Configuration parser for tool filtering and MCP-UI toggles
2020
- `src/tools/` - MCP tool implementations with `BaseTool` abstract class and registry
21+
- `src/prompts/` - MCP prompt implementations with `BasePrompt` abstract class and registry
2122
- `src/resources/` - Static reference data (style specs, token scopes, Streets v8 fields)
2223
- `src/utils/` - HTTP pipeline, JWT parsing, tracing, and version utilities
2324

2425
## Key Architectural Patterns
2526

2627
**Tool Architecture:** All tools extend `BaseTool<InputSchema, OutputSchema>`. Tools auto-validate inputs using Zod schemas. Each tool lives in `src/tools/tool-name-tool/` with separate `*.schema.ts` and `*.tool.ts` files.
2728

29+
**Prompt Architecture:** All prompts extend `BasePrompt` abstract class. Prompts orchestrate multi-step workflows, guiding AI assistants through complex tasks with best practices built-in. Each prompt lives in `src/prompts/` with separate files per prompt (e.g., `CreateAndPreviewStylePrompt.ts`). Prompts use kebab-case naming (e.g., `create-and-preview-style`).
30+
2831
**HTTP Pipeline System:** "Never patch global.fetch—use HttpPipeline with dependency injection instead." The `HttpPipeline` class applies policies (User-Agent, retry logic) via a chain-of-responsibility pattern. See `src/utils/httpPipeline.ts:20`.
2932

3033
**Resource System:** Static reference data exposed as MCP resources using URI pattern `resource://mapbox-*`, including style layer specs, Streets v8 field definitions, and token scope documentation.
3134

3235
**Token Management:** Tools receive `MAPBOX_ACCESS_TOKEN` via `extra.authInfo.token` or environment variable. Token scope validation is critical—most tool failures stem from insufficient scopes (see `README.md` for per-tool requirements).
3336

34-
**Tool Registry:** Tools are auto-discovered via `src/tools/index.ts` exports. No manual registration required—just export from index.
37+
**Tool Registry:** Tools are auto-discovered via `src/tools/toolRegistry.ts` exports. No manual registration required—just export from registry.
38+
39+
**Prompt Registry:** Prompts are registered in `src/prompts/promptRegistry.ts`. To add a new prompt, create the prompt class and add it to the `ALL_PROMPTS` array. The main server automatically registers all prompts with proper Zod schema conversion.
3540

3641
## Essential Workflows
3742

README.md

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ https://github.com/user-attachments/assets/8b1b8ef2-9fba-4951-bc9a-beaed4f6aff6
1515
- [Hosted MCP Endpoint](#hosted-mcp-endpoint)
1616
- [Getting Your Mapbox Access Token](#getting-your-mapbox-access-token)
1717
- [Tools](#tools)
18+
- [Prompts](#prompts)
1819
- [Documentation Tools](#documentation-tools)
1920
- [Reference Tools](#reference-tools)
2021
- [Style Management Tools](#style-management-tools)
@@ -453,6 +454,192 @@ An array of four numbers representing the bounding box: `[minX, minY, maxX, maxY
453454
- "Calculate the bounding box of this GeoJSON file" (then upload a .geojson file)
454455
- "What's the bounding box for the coordinates in the uploaded parks.geojson file?"
455456

457+
## Prompts
458+
459+
MCP Prompts are pre-built workflow templates that guide AI assistants through multi-step tasks. They orchestrate multiple tools in the correct sequence, providing best practices and error handling built-in.
460+
461+
**Available Prompts:**
462+
463+
### create-and-preview-style
464+
465+
Create a new Mapbox map style and generate a shareable preview link with automatic token management.
466+
467+
**Arguments:**
468+
469+
- `style_name` (required): Name for the new map style
470+
- `style_description` (optional): Description of the style theme or purpose
471+
- `base_style` (optional): Base style to start from (e.g., "streets-v12", "dark-v11")
472+
- `preview_location` (optional): Location to center the preview map
473+
- `preview_zoom` (optional): Zoom level for the preview (0-22, default: 12)
474+
475+
**What it does:**
476+
477+
1. Checks for an existing public token with `styles:read` scope
478+
2. Creates a new public token if needed
479+
3. Creates the map style
480+
4. Generates a preview link
481+
482+
**Example usage:**
483+
484+
```
485+
Use prompt: create-and-preview-style
486+
Arguments:
487+
style_name: "My Custom Map"
488+
style_description: "A dark-themed map for nighttime navigation"
489+
base_style: "dark-v11"
490+
preview_location: "San Francisco"
491+
preview_zoom: "13"
492+
```
493+
494+
### build-custom-map
495+
496+
Use conversational AI to build a custom styled map based on a theme description.
497+
498+
**Arguments:**
499+
500+
- `theme` (required): Theme description (e.g., "dark cyberpunk", "nature-focused", "minimal monochrome")
501+
- `emphasis` (optional): Features to emphasize (e.g., "parks and green spaces", "transit lines")
502+
- `preview_location` (optional): Location to center the preview map
503+
- `preview_zoom` (optional): Zoom level for the preview (0-22, default: 12)
504+
505+
**What it does:**
506+
507+
1. Uses the Style Builder tool to create a themed style based on your description
508+
2. Creates the style in your Mapbox account
509+
3. Generates a preview link
510+
511+
**Example usage:**
512+
513+
```
514+
Use prompt: build-custom-map
515+
Arguments:
516+
theme: "retro 80s neon"
517+
emphasis: "nightlife and entertainment venues"
518+
preview_location: "Tokyo"
519+
preview_zoom: "14"
520+
```
521+
522+
### analyze-geojson
523+
524+
Analyze and visualize GeoJSON data with automatic validation and bounding box calculation.
525+
526+
**Arguments:**
527+
528+
- `geojson_data` (required): GeoJSON object or string to analyze
529+
- `show_bounds` (optional): Calculate and display bounding box (true/false, default: true)
530+
- `convert_coordinates` (optional): Provide Web Mercator conversion examples (true/false, default: false)
531+
532+
**What it does:**
533+
534+
1. Validates GeoJSON format
535+
2. Calculates bounding box (if requested)
536+
3. Provides coordinate conversion examples (if requested)
537+
4. Generates an interactive visualization link
538+
539+
**Example usage:**
540+
541+
```
542+
Use prompt: analyze-geojson
543+
Arguments:
544+
geojson_data: {"type":"FeatureCollection","features":[...]}
545+
show_bounds: "true"
546+
convert_coordinates: "false"
547+
```
548+
549+
### setup-mapbox-project
550+
551+
Complete setup workflow for a new Mapbox project with proper token security and style initialization.
552+
553+
**Arguments:**
554+
555+
- `project_name` (required): Name of the project or application
556+
- `project_type` (optional): Type of project: "web", "mobile", "backend", or "fullstack" (default: "web")
557+
- `production_domain` (optional): Production domain for URL restrictions (e.g., "myapp.com")
558+
- `style_theme` (optional): Initial style theme: "light", "dark", "streets", "outdoors", "satellite" (default: "light")
559+
560+
**What it does:**
561+
562+
1. Creates development token with localhost URL restrictions
563+
2. Creates production token with domain URL restrictions (if provided)
564+
3. Creates backend secret token for server-side operations (if needed)
565+
4. Creates an initial map style using the specified theme
566+
5. Generates preview link and provides integration guidance
567+
568+
**Example usage:**
569+
570+
```
571+
Use prompt: setup-mapbox-project
572+
Arguments:
573+
project_name: "Restaurant Finder"
574+
project_type: "fullstack"
575+
production_domain: "restaurantfinder.com"
576+
style_theme: "light"
577+
```
578+
579+
### debug-mapbox-integration
580+
581+
Systematic troubleshooting workflow for diagnosing and fixing Mapbox integration issues.
582+
583+
**Arguments:**
584+
585+
- `issue_description` (required): Description of the problem (e.g., "map not loading", "401 error")
586+
- `error_message` (optional): Exact error message from console or logs
587+
- `style_id` (optional): Mapbox style ID being used, if applicable
588+
- `environment` (optional): Where the issue occurs: "development", "production", "staging"
589+
590+
**What it does:**
591+
592+
1. Verifies token validity and required scopes
593+
2. Checks style configuration and existence
594+
3. Analyzes error messages and provides specific solutions
595+
4. Tests API endpoints to isolate the problem
596+
5. Provides step-by-step fix instructions
597+
6. Offers prevention strategies
598+
599+
**Example usage:**
600+
601+
```
602+
Use prompt: debug-mapbox-integration
603+
Arguments:
604+
issue_description: "Getting 401 errors when map loads"
605+
error_message: "401 Unauthorized"
606+
style_id: "my-style-id"
607+
environment: "production"
608+
```
609+
610+
### design-data-driven-style
611+
612+
Create a map style with data-driven properties that respond dynamically to feature data using expressions.
613+
614+
**Arguments:**
615+
616+
- `style_name` (required): Name for the data-driven style
617+
- `data_description` (required): Description of the data (e.g., "population by city", "earthquake magnitudes")
618+
- `property_name` (required): Name of the data property to visualize (e.g., "population", "magnitude")
619+
- `visualization_type` (optional): How to visualize: "color", "size", "both", "heatmap" (default: "color")
620+
- `color_scheme` (optional): Color scheme: "sequential", "diverging", "categorical" (default: "sequential")
621+
622+
**What it does:**
623+
624+
1. Explains data-driven styling concepts and expressions
625+
2. Provides appropriate expression templates for your use case
626+
3. Offers color scales and size ranges based on visualization type
627+
4. Creates the style with data-driven layers
628+
5. Includes advanced expression examples (zoom-based, conditional)
629+
6. Provides best practices for accessibility and performance
630+
631+
**Example usage:**
632+
633+
```
634+
Use prompt: design-data-driven-style
635+
Arguments:
636+
style_name: "Population Density Map"
637+
data_description: "City population data"
638+
property_name: "population"
639+
visualization_type: "both"
640+
color_scheme: "sequential"
641+
```
642+
456643
## Resources
457644

458645
This server exposes static reference documentation as MCP Resources. While these are primarily accessed through the `get_reference_tool`, MCP clients that fully support the resources protocol can access them directly.

src/index.ts

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ import { SpanStatusCode } from '@opentelemetry/api';
1111

1212
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
1313
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
14+
import { z } from 'zod';
1415
import { parseToolConfigFromArgs, filterTools } from './config/toolConfig.js';
1516
import { getAllTools } from './tools/toolRegistry.js';
1617
import { getAllResources } from './resources/resourceRegistry.js';
18+
import { getAllPrompts } from './prompts/promptRegistry.js';
1719
import { getVersionInfo } from './utils/versionUtils.js';
1820
import {
1921
initializeTracing,
@@ -64,7 +66,8 @@ const server = new McpServer(
6466
{
6567
capabilities: {
6668
tools: {},
67-
resources: {}
69+
resources: {},
70+
prompts: {}
6871
}
6972
}
7073
);
@@ -80,6 +83,37 @@ resources.forEach((resource) => {
8083
resource.installTo(server);
8184
});
8285

86+
// Register prompts to the server
87+
const prompts = getAllPrompts();
88+
prompts.forEach((prompt) => {
89+
const argsSchema: Record<string, z.ZodString | z.ZodOptional<z.ZodString>> =
90+
{};
91+
92+
// Convert prompt arguments to Zod schema format
93+
prompt.arguments.forEach((arg) => {
94+
const zodString = z.string().describe(arg.description);
95+
argsSchema[arg.name] = arg.required ? zodString : zodString.optional();
96+
});
97+
98+
server.registerPrompt(
99+
prompt.name,
100+
{
101+
description: prompt.description,
102+
argsSchema: argsSchema
103+
},
104+
async (args) => {
105+
// Filter out undefined values from optional arguments
106+
const filteredArgs: Record<string, string> = {};
107+
for (const [key, value] of Object.entries(args || {})) {
108+
if (value !== undefined) {
109+
filteredArgs[key] = value;
110+
}
111+
}
112+
return prompt.execute(filteredArgs);
113+
}
114+
);
115+
});
116+
83117
async function main() {
84118
// Send MCP logging messages about .env loading
85119
if (envLoadError) {

0 commit comments

Comments
 (0)