Per-caller bearer tokens
server.auth_token is replaced by server.auth_tokens, a map of caller name to token. Every query the server logs now leads with "caller":"<name>", so the audit trail names who ran what. One person's token can be rotated or revoked without touching anyone else's.
server:
auth_tokens:
alice: ${MYSQL_MCP_TOKEN_ALICE}
bob: ${MYSQL_MCP_TOKEN_BOB}Breaking: a config still carrying server.auth_token fails at startup with the rename spelled out. There is no compatibility path. A team that wants one shared token defines one name.
- Names use the request id's charset (1–64 of letters, digits,
.,_,-); tokens must be unique and free of whitespace. Startup refuses anything else and reports"callers":N. - A token outside the set gets
401 invalid tokenand anauthwarning with the address the server saw, at most once a minute per address. A missing header gets401 no bearer token. - Under
--stdionothing checks a token and the query line carries nocaller. - The client side keeps its shape:
.mcp.jsonsendsAuthorization: Bearer ${MYSQL_MCP_AUTH_TOKEN}, and each person exports their own token under it.
Fixes
- The JSON masking integration test assumed which row holds id 1 in the seeded
bigtable, which differs between MariaDB and MySQL 8.4; CI on MySQL is green again. - The Local Development command in the README and CLAUDE.md now works from a fresh clone (
config.yamlis gitignored).
Changelog
- 49f9ba5: Issue bearer tokens per caller and log the caller on every query line (@mshddev)
- eda8cc9: Rate-limit the unknown-token warning per address (@mshddev)
- cb7eb0b: Show the upcoming version in the README startup sample (@mshddev)
- f3959ae: Stop the JSON masking tests assuming which row holds id 1 (@mshddev)
- 461da2a: Tighten the token checks and fix the dev command after review (@mshddev)