From d9197f8988d3a240ddcb5f04f924bf31b5434c37 Mon Sep 17 00:00:00 2001 From: Matthew Podwysocki Date: Tue, 10 Nov 2026 11:57:52 -0500 Subject: [PATCH 1/2] fix: list_public_tokens_tool asks the model to copy the token exactly and check it A ChatGPT-built dashboard failed with "invalid Mapbox access token" because the model retyped the pk. token and changed a character. The result now says to copy it exactly and, when it was written to a file, to check the copy from the file with GET /tokens/v2. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 4 ++++ .../ListPublicTokensTool.ts | 16 +++++++++++++++- .../ListPublicTokensTool.test.ts | 9 +++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0689a8dc..02fa3171 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## Unreleased +### Bug Fixes + +- **`list_public_tokens_tool`: asks the model to copy the token exactly and check the copy (#PR).** A dashboard ChatGPT built for For Five failed with "invalid Mapbox access token": the tool returned the right token, but the model retyped it into the page and changed a character, which is easy with about 90 characters of base64. The result now says to copy the token exactly, never retyped, and, when the agent wrote it into a file and can run commands, to check the copy from that file: `grep` the `pk.` token out of the file and call `GET /tokens/v2`, which returns `TokenValid`, or `TokenInvalid` when a character changed. Checked against the live API with a valid token and one with a single character changed. + ## 0.17.1-dev.1 - 2026-11-09 ### Bug Fixes diff --git a/src/tools/list-public-tokens-tool/ListPublicTokensTool.ts b/src/tools/list-public-tokens-tool/ListPublicTokensTool.ts index c3cd585e..96a85bb4 100644 --- a/src/tools/list-public-tokens-tool/ListPublicTokensTool.ts +++ b/src/tools/list-public-tokens-tool/ListPublicTokensTool.ts @@ -25,6 +25,20 @@ const GUIDANCE = `if none matches, ask the user to create one at ${CREATE_TOKEN_URL} (add the site's URL under URL ` + 'restrictions) and use that instead. The default token is fine for local prototypes.'; +/** + * Models often retype a long token instead of copying it, and one changed + * character makes it invalid (seen in a ChatGPT-built dashboard whose map + * failed with "invalid Mapbox access token"). Agents that write files can + * usually run commands, so this asks them to check the copy from the file. + */ +const COPY_CHECK = + 'Copy the token exactly as shown, never retyped: it is long, and one changed character makes ' + + 'Mapbox reject it with "invalid Mapbox access token". If you write it into a file and can run ' + + 'commands, check the copy from the file instead of retyping it, for example:\n' + + "TOKEN=$(grep -o 'pk\\.[A-Za-z0-9._-]*' index.html | head -1); " + + 'curl -s "https://api.mapbox.com/tokens/v2?access_token=$TOKEN"\n' + + '"code":"TokenValid" means the copy is right; "TokenInvalid" means a character changed, so copy it again.'; + /** What the Tokens API returns for each token; only pk entries are kept. */ interface ApiToken { usage?: string; @@ -243,7 +257,7 @@ export class ListPublicTokensTool extends MapboxApiBasedTool< ? `Public tokens (${output.tokens.length}):\n${lines.join('\n')}` : undefined, output.recommended - ? `Recommended: ${output.recommended.token}\n${output.recommended.reason}` + ? `Recommended: ${output.recommended.token}\n${output.recommended.reason}\n\n${COPY_CHECK}` : output.tokens.length > 0 ? 'Every public token on this account is restricted to other URLs, so none is recommended.' : 'This account has no public tokens.', diff --git a/test/tools/list-public-tokens-tool/ListPublicTokensTool.test.ts b/test/tools/list-public-tokens-tool/ListPublicTokensTool.test.ts index e7c5d0a6..4299deab 100644 --- a/test/tools/list-public-tokens-tool/ListPublicTokensTool.test.ts +++ b/test/tools/list-public-tokens-tool/ListPublicTokensTool.test.ts @@ -98,6 +98,15 @@ describe('ListPublicTokensTool', () => { 'account.mapbox.com/access-tokens/create' ); expect(textOf(result)).toContain('Recommended: pk.default.sig'); + // Models retype long tokens; the text asks them to copy it exactly and + // check the copy from the file they wrote it into. + expect(textOf(result)).toContain('never retyped'); + expect(textOf(result)).toContain( + "grep -o 'pk\\.[A-Za-z0-9._-]*' index.html" + ); + expect(textOf(result)).toContain( + 'https://api.mapbox.com/tokens/v2?access_token=$TOKEN' + ); }); it('recommends a token restricted to the site_url', async () => { From 9f1556624416022136b3c96cb71baa359a9b3051 Mon Sep 17 00:00:00 2001 From: Matthew Podwysocki Date: Tue, 10 Nov 2026 11:58:04 -0500 Subject: [PATCH 2/2] docs: add PR number to CHANGELOG Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02fa3171..678405cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ### Bug Fixes -- **`list_public_tokens_tool`: asks the model to copy the token exactly and check the copy (#PR).** A dashboard ChatGPT built for For Five failed with "invalid Mapbox access token": the tool returned the right token, but the model retyped it into the page and changed a character, which is easy with about 90 characters of base64. The result now says to copy the token exactly, never retyped, and, when the agent wrote it into a file and can run commands, to check the copy from that file: `grep` the `pk.` token out of the file and call `GET /tokens/v2`, which returns `TokenValid`, or `TokenInvalid` when a character changed. Checked against the live API with a valid token and one with a single character changed. +- **`list_public_tokens_tool`: asks the model to copy the token exactly and check the copy (#332).** A dashboard ChatGPT built for For Five failed with "invalid Mapbox access token": the tool returned the right token, but the model retyped it into the page and changed a character, which is easy with about 90 characters of base64. The result now says to copy the token exactly, never retyped, and, when the agent wrote it into a file and can run commands, to check the copy from that file: `grep` the `pk.` token out of the file and call `GET /tokens/v2`, which returns `TokenValid`, or `TokenInvalid` when a character changed. Checked against the live API with a valid token and one with a single character changed. ## 0.17.1-dev.1 - 2026-11-09