stacklok / stacklok/toolhive

Cursor LLM gateway config is a no-op: writes settings Cursor never reads

Open
#6,293 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Go
Stars
2.2k
Forks
300
Avg merge
1d 15h
Merged PRs (30d)
184

Description

Summary

thv llm setup --client cursor reports success and patches ~/Library/Application Support/Cursor/User/settings.json with:

"cursor.general.openAIBaseURL": "http://localhost:14000/v1",
"cursor.general.openAIAPIKey": "thv-proxy"

(pkg/client/config.go:517-519, via ConfigureLLMGateway in pkg/client/llm_gateway.go). The gateway proxy (thv llm proxy start) starts and responds correctly. But nothing changes in Cursor: Settings → Models → "Override OpenAI Base URL" stays off, and manually switching it on shows the stock default (https://api.openai.com/v1), not the value from settings.json.

Root cause

Checked directly against the installed Cursor client (workbench.desktop.main.js, Cursor 3.15.19). The keys ToolHive writes — openAIBaseURL / openAIAPIKey (with that exact casing, under cursor.general.*) — do not appear anywhere in the bundle. The feature Cursor actually has is openAIBaseUrl (lowercase Url) plus a separate useOpenAIKey boolean, and both are read and written exclusively through Cursor's own internal state store, not the standard VS Code configuration service:

this.reactiveStorageService.applicationUserPersistentStorage.openAIBaseUrl ?? "https://api.openai.com/v1"
...
i.setApplicationUserPersistentStorage("openAIBaseUrl", v)
i.setApplicationUserPersistentStorage("useOpenAIKey", !0)

There is no code path in the bundle that reads cursor.general.openAIBaseURL (or any cursor.general.* key) from settings.json for this feature. So ConfigureLLMGateway for Cursor patches a file/key that the current app never consults — thv llm setup succeeds and reports nothing wrong, but the integration silently does nothing.

I have not yet located where applicationUserPersistentStorage actually persists to disk — a search of ~/Library/Application Support/Cursor/User/globalStorage/state.vscdb's ItemTable for openai/baseurl/apikey-like keys came up empty, so it's under a different key format, a different table, or a different storage file entirely.

Why this needs care, not just a key-name fix

applicationUserPersistentStorage is Cursor's own internal, undocumented storage mechanism — not a stable public API surface the way settings.json is. Even once the correct persistence location is found, writing into it directly is inherently more fragile than the settings.json approach ToolHive uses for every other client, and could silently break again on a future Cursor release. Worth deciding whether:

  1. It's worth reverse-engineering and writing to Cursor's private storage anyway (accepting the fragility), or
  2. Cursor should be marked as unsupported for the LLM gateway proxy-mode integration until/unless Cursor exposes a supported configuration surface for this, or
  3. Some other integration point exists (e.g. a documented settings key for a different mechanism, or an extension-based approach) that hasn't been checked yet.

Impact

Every thv llm setup --client cursor run to date has silently failed to configure Cursor, while reporting success. Given IsClientInstalled/DetectedLLMGatewayClients both consider Cursor supported and configured, this has presumably shipped since Cursor support was added and gone unnoticed.

References

  • pkg/client/config.go:485-521 (Cursor's clientAppConfig, including the LLMGatewayKeys specs)
  • pkg/client/llm_gateway.go:39-89 (ConfigureLLMGateway, the JSON-Pointer patch path used for Cursor)
  • Related: #6292 (Cursor/VSCode detection false negatives) — that issue is about detection; this one is about the actual configuration being applied being ineffective even when detection succeeds.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in pkg/client/config.go:485-521 and pkg/client/llm_gateway.go:39-89, then trace the Cursor path used by thv llm setup --client cursor. Determine whether Cursor has a reliable supported configuration surface or whether the client should be marked unsupported; done means the chosen behavior is implemented and setup no longer silently claims success for an ineffective integration.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
cli, tooling
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.