Repository navigation
Description
Before submitting
- I searched existing issues and did not find a duplicate.
- I included enough detail to reproduce or investigate the problem.
Area
apps/server
Steps to reproduce
- Use nightly
0.0.46-nightly.20261012.3021(the samereadCursorUsageLimitslogic is onmainat6524a8d, nightly0.0.46-nightly.20261013.3053). - Sign in to the Cursor provider through T3. The SDK credential store saves an API key (
crsr_…in theapiKeyfield), not the CLI session JWT. NoCURSOR_API_KEYoverride is set on the provider instance. - On the same machine, have a normal CLI login at
~/.config/cursor/auth.json(Linux / WSL path;accessTokenis present). - Open Usage → Limits. Codex and Claude are connected on the same server.
Expected behavior
Cursor shows the plan pools GetCurrentPeriodUsage already returns for this account:
- Cursor Models (
autoPercentUsed) — Grok and Composer - Other Models (
apiPercentUsed) — Claude, GPT, and Gemini - Overall (
totalPercentUsed) when both pools are not both present - the billing-cycle reset from
billingCycleEnd
If the API key cannot read that endpoint, Limits should say so. Hiding the provider with no row and no notice makes it look like Cursor usage was never implemented.
Actual behavior
Codex and Claude limit cards show. Cursor does not. There is no error, stale state, or "usage unavailable" line.
The dashboard call explains the split:
POST https://api2.cursor.sh/aiserver.v1.DashboardService/GetCurrentPeriodUsagewith the T3-stored API key,connect-protocol-version: 1andx-cursor-client-type: cli, returns 401.- The same request with the CLI
auth.jsonaccess token returns 200 and a normalplanUsagebody. On this account that wasautoPercentUsed13.2,apiPercentUsed84.8,totalPercentUsed23.4, included-usage copy "You've used 80% of your included usage", and a monthly cycle from2026-09-23T19:40:34Zto2026-10-23T19:40:34Z.
So the data exists. T3 never asks for it while this sign-in is active, then the Limits view drops the provider.
Spend history is separate. usage-cursor-account-cache-v1.json on this machine already has about 1,600 Cursor events, read from the CLI login. This report is only the Limits cards.
Impact
Major degradation or frequent failure
Version or commit
0.0.46-nightly.20261012.3021 on the running server. Same behavior in packages/provider-cursor/src/server/usageLimits.ts and packages/shared/src/usageLimits.ts at 6524a8d43795 (0.0.46-nightly.20261013.3053).
Environment
Windows desktop, WSL backend, distro Ubuntu, WSL-only. Server is linux x64 in WSL2 (5.15.167.4-microsoft-standard-WSL2), HOME pointing at the Linux home. Cursor provider enabled. @cursor/sdk 1.0.35. Codex and Claude connected on the same server.
Logs or stack traces
No server log line. The probe returns a normal unsupported snapshot and the UI discards it.
readCursorUsageLimits bails out before any HTTP call when an API key is present and CURSOR_AUTH_TOKEN is not:
let token = environment.CURSOR_AUTH_TOKEN?.trim();
// An explicit API key can name a different account from the stored login.
if (!token && environment.CURSOR_API_KEY?.trim()) {
return makeUnavailableUsageLimits({ checkedAt, reason: "unsupported" });
}That return has no message. The driver always feeds the credential-store key in as CURSOR_API_KEY:
readCursorUsageLimits(
effectiveConfig,
{ ...processEnv, CURSOR_API_KEY: apiKey },
settings.cursorKeychainUsageEnabled,
)apiKey comes from auth.readApiKey, which loads the SDK credential (apiKey: "crsr_…"). status.ts treats a missing key as signed out ("Sign in with Cursor or add CURSOR_API_KEY in provider settings."), so the provider cannot stay authenticated and also fall through to auth.json.
The Limits view then skips the snapshot in both places:
collectLimitAccountsdrops any snapshot wherelimitsNotice()is non-null. Forreason: "unsupported"that notice is"This account has no subscription limits."collectLimitNoticesthen skipsunsupportedon purpose ("Accounts that can never report (API keys) are left out; there is nothing for the user to act on."), so that sentence is never shown either.
Net effect: an API-key Cursor sign-in, which is what the current SDK login stores, produces no Cursor row and no explanation. Codex and Claude remain.
Workaround
None that keeps this sign-in and shows the card. Removing the stored API key marks Cursor signed out, so the limits probe does not run. The source would prefer CURSOR_AUTH_TOKEN over CURSOR_API_KEY when both are set. That was not tried here, and it means copying the CLI session token into provider settings.
The short-context model bug is separate and already tracked in #15788.
Activity
bchewy commentedon Oct 15, 2026
Also observed on macOS with T3 nightly
0.0.46-nightly.20261014.3132.Cursor is browser-authenticated and account usage is enabled, but Cursor is absent from Usage → Limits. The provider snapshot reports
unsupportedwith an emptywindowsarray.The installed bundle still injects the SDK sign-in credential as
CURSOR_API_KEYwhen callingreadCursorUsageLimits. The reader returnsunsupportedbefore trying the saved CLI login.This corroborates the reported issue on macOS. I have not tested PR #19578.
rcatajar commentedon Oct 15, 2026
Workaround from the usage docs, tested with the token this server is actually configured to use.
The Cursor provider is still signed in with an API key, which
readCursorUsageLimitstreats as unsupported and which gets 401 fromGetCurrentPeriodUsage. On nightly0.0.46-nightly.20261014.3118I setCURSOR_AUTH_TOKENin the Cursor provider's environment variables to the CLI session token from~/.config/cursor/auth.json(theaccessToken, not thecrsr_…API key).Calling
POST https://api2.cursor.sh/aiserver.v1.DashboardService/GetCurrentPeriodUsagewith that stored token returns 200 andplanUsage.autoPercentUsed,planUsage.apiPercentUsed,planUsage.totalPercentUsed, plusbillingCycleEnd. That is the request the limits reader makes whenCURSOR_AUTH_TOKENis set, so it no longer takes the API-key branch that the Limits view drops with no message.The session token expires 2026-12-09T18:37:28Z. The copy in provider settings will not follow a later rewrite of
auth.json. After it expires, the limits probe should surface "Cursor could not read usage limits" until the variable is replaced. Cursor chats keep using the API key, which is a separate credential.ViDtje commentedon Oct 15, 2026
Still present on macOS nightly
0.0.46-nightly.20261015.3145. Signed in with Cursor in the browser and Cursor account usage (cursorKeychainUsageEnabled) turned on. The snapshot reportsusageLimits: { windows: [], unavailable: { reason: "unsupported" } }, with no message.readCursorUsageLimitsfinishes in about 0.05ms in the trace, so no request is made. The driver injects the sign-in API key asCURSOR_API_KEY, and the earlyCURSOR_API_KEYreturn runs before the macOS Keychain branch. The usage toggle has no effect for browser sign-ins, even when a validcursor-access-tokenis in the Keychain.joshuarossi commentedon Oct 20, 2026
Reproduced on the stable channel: desktop app v0.1.0 (macOS, local desktop-managed server, also 0.1.0). Every report above was from a nightly; v0.1.0 is the first stable release that includes #17349 (merged 2026-10-09,
b5e4f1e), so stable users lose the Cursor Limits cards when they update from v0.0.45. This machine updated on 2026-10-15 and the user's words were "I can't see my cursor usage. It used to work."Setup
serverSelfUpdate: desktop-managed)auth.type: "browser"), default instance, noCURSOR_API_KEY/CURSOR_AUTH_TOKENanywhere in settingscursorKeychainUsageEnabled: true; a valid Cursor CLI login in the macOS Keychain (cursor-agent2026.09.18,cursor-agent statusreports logged in)CursorUsageAccounts→cursor.com/api/dashboard/get-filtered-usage-events) reads fine from the same Keychain login, so the credential is good; only the Limits probe is skippedEvidence
~/.t3/caches/cursor.jsonbefore the workaround:server.trace.ndjson: everyreadCursorUsageLimitsspan today finished in 0.04–0.18 ms with no outgoing request. No request toapi2.cursor.shappears in ~9 hours of retained traces.Code path at
v0.1.0(81493ef), same as described above:packages/provider-cursor/src/server/driver.ts:234-238—readCursorUsageLimits(effectiveConfig, { ...processEnv, CURSOR_API_KEY: apiKey }, settings.cursorKeychainUsageEnabled)whereapiKeyis the browser-login SDK key fromauth.readApiKeypackages/provider-cursor/src/server/usageLimits.ts:79-82— returnsunsupported(no message) whenCURSOR_API_KEYis set andCURSOR_AUTH_TOKENis not, before the Keychain branch at L93-108packages/shared/src/usageLimits.ts:345— Limits view skips providers whose reason isunsupported, so Cursor disappears with no noticeWorkaround confirmed on stable
Added
CURSOR_AUTH_TOKEN= the Keychaincursor-access-tokenvalue as an environment variable on the Cursor provider (Settings → Providers → Cursor).mergeProviderInstanceEnvironmentputs it intoprocessEnv, the reader takes the L79 branch, and the next probe made a real request (readCursorUsageLimits2763 ms). The cache then held the expected windows:Same caveats as noted above: the token sits in plain text in
settings.jsonand will not follow CLI refreshes.Posted via
t3 triageby Claude Code running Claude Fable 5.1 (claude-fable-5-1). Triage CLI 0.1.0.bathan commentedon Oct 28, 2026
Same here on stable 0.1.3, macOS. Cursor signed in through the browser, "Cursor account usage" turned on, and Limits still comes back
unsupportedwith empty windows. The toggle doesn't change anything since theCURSOR_API_KEYcheck returns first.The account itself is fine,
GetCurrentPeriodUsagewith the Cursor app's session token gives me all three pools plus the billing cycle.One thing worth knowing for #21228: my CLI token in the Keychain had expired on Oct 19 and I never noticed, because the browser sign-in kept working. So just falling back to the Keychain wouldn't have fixed it for me. Exchanging the instance's own credential like #21228 does sounds like the right call.
Happy to try a build of #21228 against my account if you still need someone to check it on a real one.
waleed-mirza commentedon Oct 28, 2026
Also reproduced on Linux with server nightly
0.1.4-nightly.20261028.3824, andmainstill has the early returnEnvironment
t3 serve, version0.1.4-nightly.20261028.3824(Linux x64, Node 26). I checked out tagv0.1.4-nightly.20261028.3824.apiEndpointoverride and noCURSOR_*variables in the server's environment (I checked variable names only).~/.config/cursor/auth.json, with anaccessTokenand arefreshToken.Evidence
auth.status: "authenticated"andusageLimits: { windows: [], unavailable: { reason: "unsupported" } }, with nomessage.server.trace.ndjson,readCursorUsageLimitsfinishes in about 0.2 ms with a success exit. No request toapi2.cursor.shappears, so it returns before the HTTP call.driver.tspasses the sign-in key to the reader asCURSOR_API_KEY, andusageLimits.ts:81(if (!token && environment.CURSOR_API_KEY?.trim())) returnsunsupportedon it. Per the code comment this guards against a different account, but it also fires for T3's own stored key.main.Workaround confirmed
I sent
POST https://api2.cursor.sh/aiserver.v1.DashboardService/GetCurrentPeriodUsagewith theaccessTokenfromauth.jsonand theconnect-protocol-version: 1andx-cursor-client-type: cliheaders. It returned 200 withplanUsage.totalPercentUsed,autoPercentUsedandapiPercentUsed, plusbillingCycleEnd.I then added
CURSOR_AUTH_TOKEN(thataccessToken) to the Cursor instance'senvironmentinsettings.json. Within a few seconds the provider cache had three windows: Cursor Models, Other Models and Overall, all resetting on the billing-cycle end date. So the workaround in the earlier comment also works on this build.Notes for a fix
crsr_…key and the CLI session token are different credentials. When T3 holds only its own sign-in key, the reader should use the CLIauth.jsontoken, or at least show a visible "usage unavailable" message instead of anunsupportedstate with no message.cursorKeychainUsageEnabled) doesn't help here, because theCURSOR_API_KEYcheck returns first.Written by Claude Sonnet 5.5 in a Claude Code
t3 triagesession.KucherenkoIvan commentedon Oct 29, 2026
Also reproduced on the latest stable v0.1.5: macOS arm64 (Darwin 25.6.0), desktop app (T3 Code Beta) against its bundled local server, also 0.1.5.
auth.type: "browser"). NoCURSOR_API_KEYis set on the instance.cursorKeychainUsageEnabled: true, and macOS Keychain access for Cursor is allowed.usageLimits: { windows: [], unavailable: { reason: "unsupported" } }with no message.server.trace.ndjson,readCursorUsageLimitsfinishes in about 0.08 ms withSuccessand makes no request to api2.cursor.sh.I checked the code at tag
v0.1.5(6d450a4).driver.ts:237-241still passes the sign-in key asCURSOR_API_KEY, andusageLimits.ts:78-80returnsunsupportedbefore it reaches the Keychain branch, so the toggle has no effect. NeitherusageLimits.tsnor the call site indriver.tshas changed onmainsince then, so v0.1.6-nightly is affected too. Open fixes: #21228 and #26670.The user said Cursor limits used to show up and stopped at some point. They don't remember when, but it fits the move to v0.1.x. Claude limits still work.
Workaround: set
CURSOR_AUTH_TOKENin the Cursor provider instance's environment variables to the CLI token from the Keychain itemcursor-access-token/cursor-user.Triage by Claude Opus 5.5 (
claude-opus-5-5) in Claude Code, viat3 triage.noahsiegrist commentedon Nov 2, 2026
Reproduced on stable 0.1.2, Linux x64 (CachyOS). The Cursor instance uses T3's browser sign-in, and
~/.config/cursor/auth.jsonholds a valid CLI login. Inserver.trace.ndjson, all 12readCursorUsageLimitsspans finish in 0.15–1.5 ms with no HTTP child span. That matches the earlyCURSOR_API_KEYreturn inusageLimits.ts.I compared the three open fixes against
mainatac8dce0.Recommendation: #26670 is the only one that reads the instance's own account. It is also the only one that works without a host CLI login.
/auth/exchange_user_api_key, then callGetCurrentPeriodUsageauth.json/ Keychain loginapiEndpointauth.jsontoken to the custom endpoint (the file branch has no endpoint check; only the Keychain branch does)Testjob failedmain(keeping main'sdriver.test.ts)tsccleantsccleantsccleandriver.test.tsonlydriver.test.tsonlydriver.test.tsonlyLive checks against
api2.cursor.sh(to back the exchange approach; tokens not shown):GetCurrentPeriodUsagereturns 200 with fullplanUsagefor bothx-cursor-client-type: cliandsdk. So fix(cursor): show usage limits for browser sign-in #26670'ssdkheader is accepted.POST /auth/exchange_user_api_keyexists and validates user API keys: a bogus key returns401 {"message":"Invalid User API Key"}, and so does a CLI session JWT.@cursor/sdk1.0.38 makes the same exchange (POST {backend}/auth/exchange_user_api_key, bearer user key, body{}), as the PR says.crsr_key. Nobody in this thread or on the PR has run it yet.Open points on #26670 before merge:
driver.test.tsconflicts. The production code merges cleanly.CURSOR_AUTH_TOKENis read (usageLimits.ts:139vs:148). The workaround from this thread is then silently ignored. An explicit override should probably win.GetCurrentPeriodUsageitself still ends up asprobeFailed. Only an exchange 401 maps to "sign in again" (the CodeRabbit point is still open).Once #26670 lands, #28449 and #24443 can be closed.
Review done with Claude Code.
juliusmarminge commentedon Nov 9, 2026
Thanks for the detailed report! #29419, merged as af00cf73e1, exchanges the Cursor sign-in API key for a token and reads its usage limits.