Cursor mcp.json ${env:NAME} for Sume's API key: no secret in the repo
Cursor's mcp.json interpolates ${env:NAME} in headers. Keep Sume's API key in an environment variable, send one credential, and know the fixed OAuth redirects.

A project-level MCP file is easy to commit by accident, and a literal API key in it is a leak. The Cursor MCP docs show a remote server entry with url and headers, and support ${env:NAME} interpolation, read 2026-10-03. That lets a repo carry the connection to Sume's hosted MCP server without the key.
{
"mcpServers": {
"sume": {
"url": "https://mcp.sume.com/mcp",
"headers": {
"Authorization": "Bearer ${env:SUME_API_KEY}"
}
}
}
}One credential header
The Sume MCP overview says an API key goes in Authorization: Bearer or x-api-key. The REST SDK docs say the API rejects both at once with a 401 "Send only one API key credential." Choose one header, and do not repeat it in a second layer such as a proxy. If Cursor cannot see the variable, the header would be sent with an empty value; set the variable in the environment that launches Cursor and restart it.
Cursor's OAuth options
Cursor also supports a static OAuth block: auth with CLIENT_ID, optional CLIENT_SECRET and scopes. For redirects it lists http://localhost:8787/callback for the desktop app and https://www.cursor.com/agents/mcp/oauth/callback for cloud agents. Sume's OAuth page describes consent with PKCE and the scopes mcp:read (required) and mcp:write (opt-in), but the docs do not say whether a pre-registered client ID is available, so this post does not recommend the static block for Sume.
| Option | Cursor support | Sume fit |
|---|---|---|
Header with ${env:NAME} | Documented | Simple; key never in the file |
Static auth block | Documented | Not confirmed in Sume docs |
| Interactive OAuth | Documented flow | Consent shows mcp:read and mcp:write |
Approval and spend
Cursor's page says tool approval is on by default; leave it on for create tools. Sume adds its own gates: idempotency_key on every paid and write tool, max_spend_usd when you provide it, and previews through dry_run. A client timeout is not a job outcome, and jobs_wait can be re-issued with the same ids after wait_slice_expired.
- Commit the file, not the key.
- Send exactly one credential header.
- Keep tool approval on for create tools.
- Check balance before long batches with
balance_get.
Sources
Related posts
More in Developers
- Cut a voiceover into sentence clips with TTS segmentation
Sume TTS returns gapless sentence segments, cutting 70 ms after each last word by default. Per-segment audio needs wav or raw; mp3 returns timings only.
- DBOS Python durable workflow for a Sume job: resume after a crash
Submit and poll a Sume image job in a DBOS workflow: step retries, order-derived Idempotency-Key and workflow id, tested with DBOS 3.2.0 on SQLite.
- Deno 2.9 Deno.test.each: a case table for a Sume webhook verifier
Deno 2.9 adds Deno.test.each. Table-test a sume-v1 verifier: valid, rotated, empty secret, stale timestamp and tampered body, with WebCrypto only.
- Deno 2.9 t.assertSnapshot: contract-test the Sume status envelope
Deno 2.9 builds assertSnapshot into the test context. Snapshot the field names and types of GET /v1/jobs/:id/status for a completed job to catch API drift.
Written by Sume