In Short
- Problem: at the time, Cursor did not let me cleanly test the models I wanted through OpenRouter.
- What I tested: a Go proxy that exposes an OpenAI-compatible surface to Cursor, then
replaces
gpt-4owith an OpenRouter model server-side. - Result: routing worked and payloads became inspectable, but DeepSeek did not always
produce responses Cursor could apply as code edits. The local repo path was later
revalidated with Docker,
go test,go build, and an HTTP 200 call to/v1/chat/completions. - Lesson: API compatibility is not enough when the client also expects a very precise implicit behavior. This is a historical note, not a current Cursor integration recommendation.
- Linked repo:
pezzos/cursor-openrouter-proxy.
Why I Keep This Trace
The starting point was simple: let Cursor work with models other than the ones it supported natively, especially DeepSeek at the time. I did not want to rebuild the editor. I wanted to keep Cursor as the work surface while taking back control of the model called behind it.
The method was deliberately practical. Cursor expected an OpenAI-shaped endpoint, so the proxy exposed one locally. On the server side, it translated the request toward OpenRouter and swapped the requested model for the one I wanted to test.
That gave me two useful things. First, Cursor could be pointed at a local endpoint without changing the editor itself. Second, the proxy made the payloads visible. I could see what Cursor sent to the model, how large the prompts were, and what kind of responses the editor expected.
That is why I keep the trace. On paper, a shared API shape makes the pieces look easy to assemble. In practice, the client still carries implicit expectations.
What Worked
The routing itself worked. Cursor could send a request to a local OpenAI-compatible surface, and the proxy could forward it to OpenRouter. That was enough to prove the basic compatibility layer.
The experiment also made the tooling constraint visible. Cursor was not merely asking a chat model for text. It was sending large context and expecting output in a format that could become a code modification.
The useful code was tiny: Cursor kept asking for gpt-4o; the proxy accepted that
request, replaced the model server-side with the configured OpenRouter model, and sent
the real OpenRouter key from the server. The small lie was technical, but revealing:
Cursor saw a familiar surface while the proxy made the routing decision.
What Broke
The weak point was not the HTTP route. It was the behavioral contract.
Some models could answer, but not in a way Cursor could reliably use as an edit. From the outside, that can look like the model is “compatible” because the API call works. In practice, the client expects more than an API shape: it expects a style of response, enough instruction following, and a good fit with the editor’s workflow.
After the repo cleanup, a more ordinary issue also appeared: the local test script sent a
fake key that did not look like an OpenAI key, so the proxy rejected it before using the
real OpenRouter key server-side. Once the fake key used an sk-* shape, the Docker path
returned HTTP 200 with a short Hi. response. That validates the local routing path; it
still does not validate Cursor patch application.
What Still Matters
The old proxy remains useful as a small reminder: when a product says it uses a model API, the API is only one part of the system. The surrounding client behavior, prompt shape, and output expectations matter just as much.
I would not present this as a recommended way to use Cursor today. I keep it as an experiment about tool boundaries, local adapters, and the difference between protocol compatibility and product compatibility.
The repo contains the small Go proxy, Docker/Compose configuration, the expected
OpenRouter variables, a local test script for /v1/chat/completions, and RESULTATS.md
with the proof and limits of the revalidation. It is useful as a minimal example of the
routing idea. It is not a maintained Cursor integration, a guarantee that another model
will work inside Cursor, or documentation of every implicit behavior the editor expects.
The reusable rule is to inspect the payload before concluding that a model is “bad” or “compatible”. A working HTTP response is only the first contract. The product still has to parse, trust, and apply what comes back.