Skip to content

Commit 5e9bcd3

Browse files
authored
Merge pull request #13 from mapbox/token-and-gif
Update create tokens tool and README gif
2 parents c938b8d + 465e7fe commit 5e9bcd3

10 files changed

Lines changed: 44 additions & 147 deletions

README.md

Lines changed: 7 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ Complete set of tools for managing Mapbox styles via the Styles API:
107107
- **DeleteStyleTool**: Requires `styles:write` scope
108108
- **PreviewStyleTool**: Requires `tokens:read` scope (to list tokens) and at least one public token with `styles:read` scope
109109

110-
**Note:** The username is automatically extracted from the JWT token payload. Secret tokens (sk.\*) are required for write operations.
110+
**Note:** The username is automatically extracted from the JWT token payload.
111111

112112
**Example prompts:**
113113

@@ -130,31 +130,14 @@ Create a new Mapbox access token with specified scopes and optional URL restrict
130130

131131
**Available Scopes:**
132132

133-
Public scopes (can be used with public tokens):
133+
Available scopes for public tokens:
134134

135135
- `styles:tiles` - Read styles as raster tiles
136136
- `styles:read` - Read styles
137137
- `fonts:read` - Read fonts
138138
- `datasets:read` - Read datasets
139139
- `vision:read` - Read Vision API
140140

141-
Secret scopes (will create a secret token, visible only once):
142-
143-
- `scopes:list` - List available scopes
144-
- `map:read`, `map:write` - Read/write map configurations
145-
- `user:read`, `user:write` - Read/write user data
146-
- `uploads:read`, `uploads:list`, `uploads:write` - Manage uploads
147-
- `fonts:list`, `fonts:write` - List/write fonts
148-
- `styles:list`, `styles:write`, `styles:download`, `styles:protect` - Manage styles
149-
- `tokens:read`, `tokens:write` - Read/write tokens
150-
- `datasets:list`, `datasets:write` - List/write datasets
151-
- `tilesets:list`, `tilesets:read`, `tilesets:write` - Manage tilesets
152-
- `downloads:read` - Read downloads
153-
- `vision:download` - Download Vision data
154-
- `navigation:download` - Download navigation data
155-
- `offline:read`, `offline:write` - Read/write offline data
156-
- `user-feedback:read` - Read user feedback
157-
158141
**Example:**
159142

160143
```json
@@ -168,7 +151,7 @@ Secret scopes (will create a secret token, visible only once):
168151
**Example prompts:**
169152

170153
- "Create a new Mapbox token for my web app with styles:read and fonts:read permissions"
171-
- "Generate a temporary token that expires in 30 minutes with styles:tiles and vision:read scopes"
154+
- "Generate a token that expires in 30 minutes with styles:tiles and vision:read scopes"
172155
- "Create a restricted token that only works on https://myapp.com with styles:read, fonts:read, and datasets:read"
173156

174157
#### list-tokens
@@ -181,7 +164,7 @@ List Mapbox access tokens for the authenticated user with optional filtering and
181164
- `limit` (number, optional): Maximum number of tokens to return per page (1-100)
182165
- `sortby` (string, optional): Sort tokens by "created" or "modified" timestamp
183166
- `start` (string, optional): The token ID after which to start the listing (when provided, auto-pagination is disabled)
184-
- `usage` (string, optional): Filter by token type: "pk" (public), "sk" (secret), or "tk" (temporary)
167+
- `usage` (string, optional): Filter by token type: "pk" (public)
185168

186169
**Pagination behavior:**
187170

@@ -194,17 +177,17 @@ List Mapbox access tokens for the authenticated user with optional filtering and
194177
{
195178
"limit": 10,
196179
"sortby": "created",
197-
"usage": "sk"
180+
"usage": "pk"
198181
}
199182
```
200183

201184
**Example prompts:**
202185

203186
- "List all my Mapbox tokens"
204-
- "Show me my secret tokens sorted by creation date"
187+
- "Show me my public tokens sorted by creation date"
205188
- "Find my default public token"
206189
- "List the 5 most recently modified tokens"
207-
- "Show all temporary tokens in my account"
190+
- "Show all public tokens in my account"
208191

209192
### Local processing tools
210193

assets/mcp_server_devkit.gif

712 KB
Loading

docs/claude-code-integration.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ Once configured, you can use natural language to interact with Mapbox developmen
119119
### Token Management
120120

121121
- "Create a new token for my web app with styles:read and fonts:read permissions"
122-
- "List all my secret tokens"
122+
- "List all my public tokens"
123123
- "Show me my default public token"
124124

125125
### GeoJSON Processing

docs/claude-desktop-integration.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ Once configured, you can use natural language to interact with Mapbox developmen
132132
### Token Management
133133

134134
- "Create a new token for my web app with styles:read and fonts:read permissions"
135-
- "List all my secret tokens"
135+
- "List all my public tokens"
136136
- "Show me my default public token"
137137

138138
### GeoJSON Processing

src/tools/__snapshots__/tool-naming-convention.test.ts.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ exports[`Tool Naming Convention should maintain consistent tool list (snapshot t
2424
},
2525
{
2626
"className": "CreateTokenTool",
27-
"description": "Create a new Mapbox access token with specified scopes and optional URL restrictions. Token type (public/secret) is automatically determined by scopes: PUBLIC scopes (styles:tiles, styles:read, fonts:read, datasets:read, vision:read) create public tokens; SECRET scopes create secret tokens that are only visible once upon creation.",
27+
"description": "Create a new Mapbox public access token with specified scopes and optional URL restrictions.",
2828
"toolName": "create_token_tool",
2929
},
3030
{
Lines changed: 5 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,20 @@
11
import { z } from 'zod';
22

3-
// Public scopes that can be used with public tokens
4-
const PUBLIC_SCOPES = [
3+
// Valid scopes for public tokens
4+
const SCOPES = [
55
'styles:tiles',
66
'styles:read',
77
'fonts:read',
88
'datasets:read',
99
'vision:read'
1010
] as const;
1111

12-
// Secret scopes that can only be used with secret tokens
13-
const SECRET_SCOPES = [
14-
'scopes:list',
15-
'map:read',
16-
'map:write',
17-
'user:read',
18-
'user:write',
19-
'uploads:read',
20-
'uploads:list',
21-
'uploads:write',
22-
'fonts:list',
23-
'fonts:write',
24-
'styles:write',
25-
'styles:list',
26-
'styles:download',
27-
'styles:protect',
28-
'tokens:read',
29-
'tokens:write',
30-
'datasets:list',
31-
'datasets:write',
32-
'tilesets:list',
33-
'tilesets:read',
34-
'tilesets:write',
35-
'downloads:read',
36-
'vision:download',
37-
'navigation:download',
38-
'offline:read',
39-
'offline:write',
40-
'user-feedback:read'
41-
] as const;
42-
43-
// All valid scopes
44-
const ALL_SCOPES = [...PUBLIC_SCOPES, ...SECRET_SCOPES] as const;
45-
4612
export const CreateTokenSchema = z.object({
4713
note: z.string().describe('Description of the token'),
4814
scopes: z
49-
.array(z.enum(ALL_SCOPES))
15+
.array(z.enum(SCOPES))
5016
.describe(
51-
'Array of scopes/permissions for the token. PUBLIC scopes (styles:tiles, styles:read, fonts:read, datasets:read, vision:read) create a public token. SECRET scopes (all others) create a secret token. If any secret scope is included, the entire token becomes secret and will only be visible once upon creation.'
17+
'Array of scopes/permissions for the public token. Valid scopes: styles:tiles, styles:read, fonts:read, datasets:read, vision:read.'
5218
),
5319
allowedUrls: z
5420
.array(z.string())
@@ -65,4 +31,4 @@ export const CreateTokenSchema = z.object({
6531
export type CreateTokenInput = z.infer<typeof CreateTokenSchema>;
6632

6733
// Export scopes for potential reuse
68-
export { PUBLIC_SCOPES, SECRET_SCOPES, ALL_SCOPES };
34+
export { SCOPES };

src/tools/create-token-tool/CreateTokenTool.test.ts

Lines changed: 6 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ describe('CreateTokenTool', () => {
3030
it('should have correct name and description', () => {
3131
expect(tool.name).toBe('create_token_tool');
3232
expect(tool.description).toBe(
33-
'Create a new Mapbox access token with specified scopes and optional URL restrictions. Token type (public/secret) is automatically determined by scopes: PUBLIC scopes (styles:tiles, styles:read, fonts:read, datasets:read, vision:read) create public tokens; SECRET scopes create secret tokens that are only visible once upon creation.'
33+
'Create a new Mapbox public access token with specified scopes and optional URL restrictions.'
3434
);
3535
});
3636

@@ -219,11 +219,11 @@ describe('CreateTokenTool', () => {
219219
]);
220220
});
221221

222-
it('creates a temporary token with expiration', async () => {
222+
it('creates a token with expiration', async () => {
223223
const expiresAt = '2024-12-31T23:59:59.000Z';
224224
const mockResponse = {
225-
token: 'tk.eyJ1IjoidGVzdHVzZXIiLCJhIjoiY2xwMTIzNDU2In0.test',
226-
note: 'Temporary token',
225+
token: 'pk.eyJ1IjoidGVzdHVzZXIiLCJhIjoiY2xwMTIzNDU2In0.test',
226+
note: 'Token with expiration',
227227
id: 'cktest789',
228228
scopes: ['styles:read'],
229229
created: '2024-01-01T00:00:00.000Z',
@@ -238,7 +238,7 @@ describe('CreateTokenTool', () => {
238238
} as Response);
239239

240240
const result = await tool.run({
241-
note: 'Temporary token',
241+
note: 'Token with expiration',
242242
scopes: ['styles:read'],
243243
expires: expiresAt
244244
});
@@ -253,36 +253,6 @@ describe('CreateTokenTool', () => {
253253
expect(requestBody.expires).toEqual(expiresAt);
254254
});
255255

256-
it('logs warning when creating token with secret scopes', async () => {
257-
const mockResponse = {
258-
token: 'sk.eyJ1IjoidGVzdHVzZXIiLCJhIjoiY2xwMTIzNDU2In0.secret',
259-
note: 'Secret token',
260-
id: 'cksecret123',
261-
scopes: ['tokens:write', 'styles:write'],
262-
created: '2024-01-01T00:00:00.000Z',
263-
modified: '2024-01-01T00:00:00.000Z'
264-
};
265-
266-
const fetchMock = setupFetch();
267-
fetchMock.mockResolvedValueOnce({
268-
ok: true,
269-
json: async () => mockResponse
270-
} as Response);
271-
272-
const result = await tool.run({
273-
note: 'Secret token',
274-
scopes: ['tokens:write', 'styles:write']
275-
});
276-
277-
expect(result.isError).toBe(false);
278-
279-
// Verify the warning was logged
280-
expect(tool['log']).toHaveBeenCalledWith(
281-
'info',
282-
'CreateTokenTool: Creating a SECRET token due to secret scopes. This token will only be visible once upon creation.'
283-
);
284-
});
285-
286256
it('handles API errors gracefully', async () => {
287257
const fetchMock = setupFetch();
288258
fetchMock.mockResolvedValueOnce({
@@ -295,7 +265,7 @@ describe('CreateTokenTool', () => {
295265

296266
const result = await tool.run({
297267
note: 'Test token',
298-
scopes: ['tokens:write']
268+
scopes: ['styles:read']
299269
});
300270

301271
expect(result.isError).toBe(true);

src/tools/create-token-tool/CreateTokenTool.ts

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
import { MapboxApiBasedTool } from '../MapboxApiBasedTool.js';
22
import {
33
CreateTokenSchema,
4-
CreateTokenInput,
5-
SECRET_SCOPES
4+
CreateTokenInput
65
} from './CreateTokenTool.schema.js';
76

87
export class CreateTokenTool extends MapboxApiBasedTool<
98
typeof CreateTokenSchema
109
> {
1110
readonly name = 'create_token_tool';
1211
readonly description =
13-
'Create a new Mapbox access token with specified scopes and optional URL restrictions. Token type (public/secret) is automatically determined by scopes: PUBLIC scopes (styles:tiles, styles:read, fonts:read, datasets:read, vision:read) create public tokens; SECRET scopes create secret tokens that are only visible once upon creation.';
12+
'Create a new Mapbox public access token with specified scopes and optional URL restrictions.';
1413

1514
constructor() {
1615
super({ inputSchema: CreateTokenSchema });
@@ -24,26 +23,9 @@ export class CreateTokenTool extends MapboxApiBasedTool<
2423

2524
this.log(
2625
'info',
27-
`CreateTokenTool: Starting token creation with note: "${input.note}", scopes: ${JSON.stringify(input.scopes)}`
26+
`CreateTokenTool: Creating public token with note: "${input.note}", scopes: ${JSON.stringify(input.scopes)}`
2827
);
2928

30-
// Check if any secret scopes are being used
31-
const hasSecretScopes = input.scopes.some((scope) =>
32-
SECRET_SCOPES.includes(scope as (typeof SECRET_SCOPES)[number])
33-
);
34-
35-
if (hasSecretScopes) {
36-
this.log(
37-
'info',
38-
'CreateTokenTool: Creating a SECRET token due to secret scopes. This token will only be visible once upon creation.'
39-
);
40-
} else {
41-
this.log(
42-
'info',
43-
'CreateTokenTool: Creating a PUBLIC token (only public scopes detected).'
44-
);
45-
}
46-
4729
const url = `${MapboxApiBasedTool.MAPBOX_API_ENDPOINT}tokens/v2/${username}?access_token=${accessToken}`;
4830

4931
const body: {

src/tools/list-tokens-tool/ListTokensTool.schema.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,7 @@ export const ListTokensSchema = z.object({
1616
.optional()
1717
.describe('Sort tokens by created or modified timestamp'),
1818
start: z.string().optional().describe('Token ID to start pagination from'),
19-
usage: z
20-
.enum(['pk', 'sk', 'tk'])
21-
.optional()
22-
.describe('Filter by token type: pk (public), sk (secret), tk (temporary)')
19+
usage: z.enum(['pk']).optional().describe('Filter by token type: pk (public)')
2320
});
2421

2522
export type ListTokensInput = z.infer<typeof ListTokensSchema>;

0 commit comments

Comments
 (0)