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
7 changes: 6 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,25 @@ The codebase organizes into:
- `src/index.ts` - Main entry point with .env loading and server initialization
- `src/config/toolConfig.ts` - Configuration parser for tool filtering and MCP-UI toggles
- `src/tools/` - MCP tool implementations with `BaseTool` abstract class and registry
- `src/prompts/` - MCP prompt implementations with `BasePrompt` abstract class and registry
- `src/resources/` - Static reference data (style specs, token scopes, Streets v8 fields)
- `src/utils/` - HTTP pipeline, JWT parsing, tracing, and version utilities

## Key Architectural Patterns

**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.

**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`).

**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`.

**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.

**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).

**Tool Registry:** Tools are auto-discovered via `src/tools/index.ts` exports. No manual registration required—just export from index.
**Tool Registry:** Tools are auto-discovered via `src/tools/toolRegistry.ts` exports. No manual registration required—just export from registry.

**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.

## Essential Workflows

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

## Prompts

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.

**Available Prompts:**

### create-and-preview-style

Create a new Mapbox map style and generate a shareable preview link with automatic token management.

**Arguments:**

- `style_name` (required): Name for the new map style
- `style_description` (optional): Description of the style theme or purpose
- `base_style` (optional): Base style to start from (e.g., "streets-v12", "dark-v11")
- `preview_location` (optional): Location to center the preview map
- `preview_zoom` (optional): Zoom level for the preview (0-22, default: 12)

**What it does:**

1. Checks for an existing public token with `styles:read` scope
2. Creates a new public token if needed
3. Creates the map style
4. Generates a preview link

**Example usage:**

```
Use prompt: create-and-preview-style
Arguments:
style_name: "My Custom Map"
style_description: "A dark-themed map for nighttime navigation"
base_style: "dark-v11"
preview_location: "San Francisco"
preview_zoom: "13"
```

### build-custom-map

Use conversational AI to build a custom styled map based on a theme description.

**Arguments:**

- `theme` (required): Theme description (e.g., "dark cyberpunk", "nature-focused", "minimal monochrome")
- `emphasis` (optional): Features to emphasize (e.g., "parks and green spaces", "transit lines")
- `preview_location` (optional): Location to center the preview map
- `preview_zoom` (optional): Zoom level for the preview (0-22, default: 12)

**What it does:**

1. Uses the Style Builder tool to create a themed style based on your description
2. Creates the style in your Mapbox account
3. Generates a preview link

**Example usage:**

```
Use prompt: build-custom-map
Arguments:
theme: "retro 80s neon"
emphasis: "nightlife and entertainment venues"
preview_location: "Tokyo"
preview_zoom: "14"
```

### analyze-geojson

Analyze and visualize GeoJSON data with automatic validation and bounding box calculation.

**Arguments:**

- `geojson_data` (required): GeoJSON object or string to analyze
- `show_bounds` (optional): Calculate and display bounding box (true/false, default: true)
- `convert_coordinates` (optional): Provide Web Mercator conversion examples (true/false, default: false)

**What it does:**

1. Validates GeoJSON format
2. Calculates bounding box (if requested)
3. Provides coordinate conversion examples (if requested)
4. Generates an interactive visualization link

**Example usage:**

```
Use prompt: analyze-geojson
Arguments:
geojson_data: {"type":"FeatureCollection","features":[...]}
show_bounds: "true"
convert_coordinates: "false"
```

### setup-mapbox-project

Complete setup workflow for a new Mapbox project with proper token security and style initialization.

**Arguments:**

- `project_name` (required): Name of the project or application
- `project_type` (optional): Type of project: "web", "mobile", "backend", or "fullstack" (default: "web")
- `production_domain` (optional): Production domain for URL restrictions (e.g., "myapp.com")
- `style_theme` (optional): Initial style theme: "light", "dark", "streets", "outdoors", "satellite" (default: "light")

**What it does:**

1. Creates development token with localhost URL restrictions
2. Creates production token with domain URL restrictions (if provided)
3. Creates backend secret token for server-side operations (if needed)
4. Creates an initial map style using the specified theme
5. Generates preview link and provides integration guidance

**Example usage:**

```
Use prompt: setup-mapbox-project
Arguments:
project_name: "Restaurant Finder"
project_type: "fullstack"
production_domain: "restaurantfinder.com"
style_theme: "light"
```

### debug-mapbox-integration

Systematic troubleshooting workflow for diagnosing and fixing Mapbox integration issues.

**Arguments:**

- `issue_description` (required): Description of the problem (e.g., "map not loading", "401 error")
- `error_message` (optional): Exact error message from console or logs
- `style_id` (optional): Mapbox style ID being used, if applicable
- `environment` (optional): Where the issue occurs: "development", "production", "staging"

**What it does:**

1. Verifies token validity and required scopes
2. Checks style configuration and existence
3. Analyzes error messages and provides specific solutions
4. Tests API endpoints to isolate the problem
5. Provides step-by-step fix instructions
6. Offers prevention strategies

**Example usage:**

```
Use prompt: debug-mapbox-integration
Arguments:
issue_description: "Getting 401 errors when map loads"
error_message: "401 Unauthorized"
style_id: "my-style-id"
environment: "production"
```

### design-data-driven-style

Create a map style with data-driven properties that respond dynamically to feature data using expressions.

**Arguments:**

- `style_name` (required): Name for the data-driven style
- `data_description` (required): Description of the data (e.g., "population by city", "earthquake magnitudes")
- `property_name` (required): Name of the data property to visualize (e.g., "population", "magnitude")
- `visualization_type` (optional): How to visualize: "color", "size", "both", "heatmap" (default: "color")
- `color_scheme` (optional): Color scheme: "sequential", "diverging", "categorical" (default: "sequential")

**What it does:**

1. Explains data-driven styling concepts and expressions
2. Provides appropriate expression templates for your use case
3. Offers color scales and size ranges based on visualization type
4. Creates the style with data-driven layers
5. Includes advanced expression examples (zoom-based, conditional)
6. Provides best practices for accessibility and performance

**Example usage:**

```
Use prompt: design-data-driven-style
Arguments:
style_name: "Population Density Map"
data_description: "City population data"
property_name: "population"
visualization_type: "both"
color_scheme: "sequential"
```

## Resources

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.
Expand Down
36 changes: 35 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ import { SpanStatusCode } from '@opentelemetry/api';

import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { z } from 'zod';
import { parseToolConfigFromArgs, filterTools } from './config/toolConfig.js';
import { getAllTools } from './tools/toolRegistry.js';
import { getAllResources } from './resources/resourceRegistry.js';
import { getAllPrompts } from './prompts/promptRegistry.js';
import { getVersionInfo } from './utils/versionUtils.js';
import {
initializeTracing,
Expand Down Expand Up @@ -64,7 +66,8 @@ const server = new McpServer(
{
capabilities: {
tools: {},
resources: {}
resources: {},
prompts: {}
}
}
);
Expand All @@ -80,6 +83,37 @@ resources.forEach((resource) => {
resource.installTo(server);
});

// Register prompts to the server
const prompts = getAllPrompts();
prompts.forEach((prompt) => {
const argsSchema: Record<string, z.ZodString | z.ZodOptional<z.ZodString>> =
{};

// Convert prompt arguments to Zod schema format
prompt.arguments.forEach((arg) => {
const zodString = z.string().describe(arg.description);
argsSchema[arg.name] = arg.required ? zodString : zodString.optional();
});

server.registerPrompt(
prompt.name,
{
description: prompt.description,
argsSchema: argsSchema
},
async (args) => {
// Filter out undefined values from optional arguments
const filteredArgs: Record<string, string> = {};
for (const [key, value] of Object.entries(args || {})) {
if (value !== undefined) {
filteredArgs[key] = value;
}
}
return prompt.execute(filteredArgs);
}
);
});

async function main() {
// Send MCP logging messages about .env loading
if (envLoadError) {
Expand Down
Loading
Loading