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
120 changes: 120 additions & 0 deletions TOOL_CONFIGURATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Tool Configuration Guide

The Mapbox MCP Devkit Server supports command-line configuration to enable or disable specific tools at startup.

## Command-Line Options

### --enable-tools

Enable only specific tools (exclusive mode). When this option is used, only the listed tools will be available.

```bash
<command> --enable-tools list_styles_tool,create_style_tool
```

### --disable-tools

Disable specific tools. All other tools will remain enabled.

```bash
<command> --disable-tools delete_style_tool,update_style_tool
```

## Available Tools

The following tools are available in the Mapbox MCP Devkit Server:

### Style Management Tools

- `list_styles_tool` - List all Mapbox styles
- `create_style_tool` - Create a new Mapbox style
- `retrieve_style_tool` - Retrieve details of a specific style
- `update_style_tool` - Update an existing Mapbox style
- `delete_style_tool` - Delete a Mapbox style
- `preview_style_tool` - Generate a preview image of a Mapbox style

### Visualization Tools

- `geojson_preview_tool` - Generate a preview map with GeoJSON data overlay

### Token Management Tools

- `create_token_tool` - Create a new Mapbox access token
- `list_tokens_tool` - List all Mapbox access tokens

### Geographic Tools

- `bounding_box_tool` - Calculate bounding box for given coordinates
- `country_bounding_box_tool` - Get bounding box for a specific country
- `coordinate_conversion_tool` - Convert between different coordinate formats

## Usage Examples

### Node.js

```bash
node dist/index.js --enable-tools list_styles_tool,create_style_tool,preview_style_tool
```

### NPX

```bash
npx @mapbox/mcp-devkit-server --disable-tools delete_style_tool,update_style_tool
```

### Docker

```bash
docker run mapbox/mcp-devkit-server --enable-tools geojson_preview_tool,preview_style_tool,coordinate_conversion_tool
```

### Claude Desktop App Configuration

In your Claude Desktop configuration file:

```json
{
"mcpServers": {
"mapbox-devkit": {
"command": "node",
"args": [
"/path/to/mcp-devkit-server/dist/index.js",
"--enable-tools",
"list_styles_tool,create_style_tool,preview_style_tool"
],
"env": {
"MAPBOX_ACCESS_TOKEN": "your-mapbox-token-here"
}
}
}
}
```

## Example Configurations

### Enable only read-only tools (safe mode)

```bash
node dist/index.js --enable-tools list_styles_tool,retrieve_style_tool,list_tokens_tool,preview_style_tool
```

### Enable only style management tools

```bash
node dist/index.js --enable-tools list_styles_tool,create_style_tool,retrieve_style_tool,update_style_tool,delete_style_tool,preview_style_tool
```

### Disable dangerous operations

```bash
node dist/index.js --disable-tools delete_style_tool,create_token_tool
```

## Notes

- If both `--enable-tools` and `--disable-tools` are provided, `--enable-tools` takes precedence
- Tool names must match exactly (case-sensitive)
- Multiple tools can be specified using comma separation
- Invalid tool names are silently ignored
- Arguments are passed after the main command, regardless of how the server is invoked
- All tools require a valid Mapbox access token set in the `MAPBOX_ACCESS_TOKEN` environment variable
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"dxt_version": "0.1",
"name": "@mapbox/mcp-devkit-server",
"display_name": "Mapbox MCP DevKit Server",
"version": "0.2.3",
"version": "0.3.0",
"description": "Mapbox MCP devkit server",
"author": {
"name": "Mapbox, Inc."
Expand Down
233 changes: 233 additions & 0 deletions src/config/toolConfig.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
import {
describe,
it,
expect,
beforeEach,
afterAll,
jest
} from '@jest/globals';
import {
parseToolConfigFromArgs,
filterTools,
ToolConfig
} from './toolConfig.js';

// Mock getVersionInfo to avoid import.meta.url issues in Jest
jest.mock('../utils/versionUtils.js', () => ({
getVersionInfo: jest.fn(() => ({
name: 'Mapbox MCP devkit server',
version: '1.0.0',
sha: 'mock-sha',
tag: 'mock-tag',
branch: 'mock-branch'
}))
}));

describe('Tool Configuration', () => {
// Save original argv
const originalArgv = process.argv;

beforeEach(() => {
// Reset argv before each test
process.argv = [...originalArgv];
});

afterAll(() => {
// Restore original argv
process.argv = originalArgv;
});

describe('parseToolConfigFromArgs', () => {
it('should return empty config when no arguments provided', () => {
process.argv = ['node', 'index.js'];
const config = parseToolConfigFromArgs();
expect(config).toEqual({});
});

it('should parse --enable-tools with single tool', () => {
process.argv = ['node', 'index.js', '--enable-tools', 'list_styles_tool'];
const config = parseToolConfigFromArgs();
expect(config).toEqual({
enabledTools: ['list_styles_tool']
});
});

it('should parse --enable-tools with multiple tools', () => {
process.argv = [
'node',
'index.js',
'--enable-tools',
'list_styles_tool,create_style_tool,preview_style_tool'
];
const config = parseToolConfigFromArgs();
expect(config).toEqual({
enabledTools: [
'list_styles_tool',
'create_style_tool',
'preview_style_tool'
]
});
});

it('should trim whitespace from tool names', () => {
process.argv = [
'node',
'index.js',
'--enable-tools',
'list_styles_tool , create_style_tool , preview_style_tool'
];
const config = parseToolConfigFromArgs();
expect(config).toEqual({
enabledTools: [
'list_styles_tool',
'create_style_tool',
'preview_style_tool'
]
});
});

it('should parse --disable-tools with single tool', () => {
process.argv = [
'node',
'index.js',
'--disable-tools',
'delete_style_tool'
];
const config = parseToolConfigFromArgs();
expect(config).toEqual({
disabledTools: ['delete_style_tool']
});
});

it('should parse --disable-tools with multiple tools', () => {
process.argv = [
'node',
'index.js',
'--disable-tools',
'delete_style_tool,update_style_tool'
];
const config = parseToolConfigFromArgs();
expect(config).toEqual({
disabledTools: ['delete_style_tool', 'update_style_tool']
});
});

it('should parse both --enable-tools and --disable-tools', () => {
process.argv = [
'node',
'index.js',
'--enable-tools',
'list_styles_tool',
'--disable-tools',
'delete_style_tool'
];
const config = parseToolConfigFromArgs();
expect(config).toEqual({
enabledTools: ['list_styles_tool'],
disabledTools: ['delete_style_tool']
});
});

it('should handle missing value for --enable-tools', () => {
process.argv = ['node', 'index.js', '--enable-tools'];
const config = parseToolConfigFromArgs();
expect(config).toEqual({});
});

it('should handle missing value for --disable-tools', () => {
process.argv = ['node', 'index.js', '--disable-tools'];
const config = parseToolConfigFromArgs();
expect(config).toEqual({});
});

it('should ignore unknown arguments', () => {
process.argv = [
'node',
'index.js',
'--unknown-arg',
'value',
'--enable-tools',
'list_styles_tool'
];
const config = parseToolConfigFromArgs();
expect(config).toEqual({
enabledTools: ['list_styles_tool']
});
});
});

describe('filterTools', () => {
// Mock tools for testing
const mockTools = [
{ name: 'list_styles_tool', description: 'List styles' },
{ name: 'create_style_tool', description: 'Create style' },
{ name: 'delete_style_tool', description: 'Delete style' },
{ name: 'preview_style_tool', description: 'Preview style' }
] as any;

Check warning on line 166 in src/config/toolConfig.test.ts

View workflow job for this annotation

GitHub Actions / test

Unexpected any. Specify a different type

it('should return all tools when no config provided', () => {
const config: ToolConfig = {};
const filtered = filterTools(mockTools, config);
expect(filtered).toEqual(mockTools);
});

it('should filter tools based on enabledTools', () => {
const config: ToolConfig = {
enabledTools: ['list_styles_tool', 'create_style_tool']
};
const filtered = filterTools(mockTools, config);
expect(filtered).toHaveLength(2);
expect(filtered.map((t) => t.name)).toEqual([
'list_styles_tool',
'create_style_tool'
]);
});

it('should filter tools based on disabledTools', () => {
const config: ToolConfig = {
disabledTools: ['delete_style_tool', 'preview_style_tool']
};
const filtered = filterTools(mockTools, config);
expect(filtered).toHaveLength(2);
expect(filtered.map((t) => t.name)).toEqual([
'list_styles_tool',
'create_style_tool'
]);
});

it('should prioritize enabledTools over disabledTools', () => {
const config: ToolConfig = {
enabledTools: ['list_styles_tool'],
disabledTools: ['list_styles_tool', 'create_style_tool']
};
const filtered = filterTools(mockTools, config);
expect(filtered).toHaveLength(1);
expect(filtered.map((t) => t.name)).toEqual(['list_styles_tool']);
});

it('should handle non-existent tool names gracefully', () => {
const config: ToolConfig = {
enabledTools: ['list_styles_tool', 'non_existent_tool']
};
const filtered = filterTools(mockTools, config);
expect(filtered).toHaveLength(1);
expect(filtered.map((t) => t.name)).toEqual(['list_styles_tool']);
});

it('should return empty array when enabledTools is empty', () => {
const config: ToolConfig = {
enabledTools: []
};
const filtered = filterTools(mockTools, config);
expect(filtered).toHaveLength(0);
});

it('should return all tools when disabledTools is empty', () => {
const config: ToolConfig = {
disabledTools: []
};
const filtered = filterTools(mockTools, config);
expect(filtered).toEqual(mockTools);
});
});
});
Loading
Loading