Scope each MCP tool's token before you launch its server
You'll create dedicated least-privilege tokens for each MCP server and wire them into launch config, so a leaked token is limited to what that tool really needs and is not committed to disk.
- List tool operationsOnly actions the server actually needs
- Create scoped tokenDedicated credential per tool
- Wire via input prompts${input:...} / password: true in VS Code
- Launch MCP serverUse scoped credential, not remote bearer
- Run a normal requestWiden only missing scope if needed
Why it matters
The Sentry thread is a good warning: the remote endpoint is OAuth-only, token auth has not been prioritized, and people in sandboxed environments ended up reimplementing tools instead of using a bearer token (thread (opens external site)). If you paste a broad personal token into an MCP config anyway, you have created a long-lived credential that can reach far beyond the one tool. You want each MCP server to run with a dedicated token whose scopes match only the operations that tool performs, and to keep that token out of committed config.
Steps
-
List the operations each MCP tool actually needs, then create one dedicated credential per tool with only those scopes. Don't reuse a full-access personal token; a leak in one server should not become a key to everything.
-
Prefer OAuth for interactive clients when the provider supports it. If you use MCP Inspector, be careful: it is designed as a public client. A proposed fix for issue #683 would let the guided OAuth flow use a manually entered client ID, but it does not support a client secret. The thread says it should be fixed by PR #684 but does not confirm the PR was merged or verified, so check your build before relying on that behavior.
-
Wire the credential into the server config without writing it to disk. In VS Code, the team's tracking issue proposed configuring MCP servers in
.vscode/mcp.jsonor anmcpsection insettings.json. Its base example follows Claude Desktop's shape:
{
"mcpServers": {
"postgres-server": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres", "postgresql://localhost/mydb"],
"env": {}
}
}
}
The same thread's second sample uses a top-level servers key, so the key name is not settled in the thread. For secrets, it proposed reusing the inputs mechanism with ${input:...} references and password: true, so the secret is prompted and not committed.
-
For headless service accounts that cannot finish an OAuth redirect, bind the access token to the stdio binary rather than a remote HTTP endpoint. For Sentry, a maintainer suggested executing
npx @sentry/mcp-server; the remote endpoint remains OAuth-only, and theAuthorization: Bearer <token>header was only a proposal, not tested or confirmed. -
Rotate tokens that have already been pasted into chats, logs, or config files, and create a fresh scoped token before launching. If you don't know whether a token leaked, treat it as exposed.
-
Launch the server and run one normal request. If the scoped token is too narrow, widen only the missing scope and test again. Avoid starting with a broad token and trying to shrink it later.
Common mistakes
- Committing a real token in
.vscode/mcp.json,.mcp.json, or anenvblock; use the input-prompt or secret-storage route instead. - Assuming the remote Sentry endpoint accepts
Authorization: Bearer <token>; the thread shows that was only a proposal and the endpoint is OAuth-only. - Reusing one broad access token across every MCP tool; a single incident then exposes everything that token can reach.
- Trying to configure MCP Inspector with a client secret; the proposed change supports only a manually entered client ID because Inspector acts as a public client.
Checklist
0 of 8 done