Skip to content

Commit 7f17aa2

Browse files
committed
docs: catch README/CHANGELOG up to MCP re-forwarding and ordering fix
- MCP section: live per-turn forwarding via chat.params (mcp.status + config.get), OAuth client mapping to the Cursor auth block, the unshareable-OAuth skip + one-time toast, and the session-reuse interaction (changed set -> fresh agent; tools sit atop the cache-prefix hierarchy). - Session reuse table: add the MCP-set-changed row. - Cache implications: MCP changes listed among prefix re-seeders. - CHANGELOG: entries for MCP re-forwarding and the tool-block part ordering fix.
1 parent 4841bab commit 7f17aa2

2 files changed

Lines changed: 40 additions & 4 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,24 @@ All notable changes to this project will be documented in this file.
2525
TTL, 200-entry LRU cap), so the first turn after a restart resumes the
2626
session's Cursor agent — whose conversation lives in Cursor's own checkpoint
2727
store — instead of paying a cache-cold full-transcript replay.
28+
- **MCP servers are re-forwarded live, per turn, with OAuth mapping.** The
29+
`config` hook's startup snapshot meant mid-session MCP enable/disable never
30+
reached the Cursor agent. The `chat.params` hook now forwards the live set
31+
each turn (`client.mcp.status()` for runtime truth, `client.config.get()` for
32+
launch specs). Because a resumed agent keeps its original servers, a changed
33+
set forces a fresh agent (full-transcript replay, re-pooled) so the new
34+
servers take effect — the session fingerprint carries an `mcpHash` for this.
35+
Remote servers with a registered OAuth client are forwarded with a Cursor
36+
`auth` block so the agent runs its own OAuth flow; servers needing OAuth
37+
without a shareable `clientId` (dynamic registration) are skipped with a
38+
one-time toast instead of forwarding a spec that would 401.
39+
- **Fixed: text/reasoning streamed after a tool call rendered above the tool
40+
block.** The earlier ordering fix closed parts on text↔reasoning transitions,
41+
but blocks-mode tool parts were emitted while the narration part stayed open
42+
— and hosts position a part where it started. Open text/reasoning parts are
43+
now closed before tool parts are emitted (except for buffered edit calls,
44+
which emit nothing until their result arrives, so narration isn't split
45+
needlessly).
2846
- **Tool outputs are included (truncated) in flattened transcripts.** The
2947
fresh/divergence/`session: false` replay paths previously dropped Cursor tool
3048
results to bare `[result of X]` placeholders, so a fresh agent re-read a

‎README.md‎

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ classifies each turn:
175175
| First turn of the session | **new** | fresh agent, full transcript, pool it |
176176
| System prompt differs (title gen and other side calls) | **side-call** | fresh ephemeral agent; the pooled agent is left untouched |
177177
| Prior user sequence is an exact prefix + exactly one new user message | **continuation** | `Agent.resume` the pooled agent, send **only** the new message |
178+
| Continuation, but the forwarded MCP server set changed | **continuation** (fresh agent) | fresh agent + full transcript, re-pool — a resumed agent keeps its original MCP servers, so a fresh one is needed for the new set |
178179
| Earlier message edited/reverted, conversation compacted, or several messages queued | **divergence** | fresh agent, full transcript, re-pool |
179180

180181
The worst case on any misclassification is a single full-transcript replay that self-heals on the
@@ -193,7 +194,8 @@ checkpoint store, and the next turn resumes it instead of replaying the transcri
193194
cache (Anthropic uses a ~5-minute sliding TTL) decides hits. `"auto"` keeps the prompt prefix stable
194195
across turns, which is what lands cache reads instead of expensive re-seeds. Things that re-seed the
195196
cache even mid-window: switching model/variant, changing the thinking level, toggling agent/plan
196-
mode, or editing an earlier message (all change the exact token prefix). Tool outputs from earlier
197+
mode, editing an earlier message, or changing the forwarded MCP server set (tool definitions sit at
198+
the top of the provider's cache-prefix hierarchy, so they invalidate everything after them). Tool outputs from earlier
197199
turns are included (truncated) in the replay paths so a fresh/diverged agent still sees what prior
198200
tools produced. Set `OPENCODE_CURSOR_DEBUG=1` to log the per-turn classification and the
199201
`cacheReadTokens`/`cacheWriteTokens` reported by Cursor.
@@ -236,20 +238,36 @@ To disable MCP forwarding, set `provider.cursor.options.forwardMcp: false` in yo
236238

237239
## MCP servers
238240

239-
The Cursor agent can use the **same MCP servers you've configured in opencode**. The plugin's
240-
`config` hook reads opencode's `config.mcp`, translates each entry into the Cursor SDK's
241-
`McpServerConfig` shape, and hands them to the agent via `Agent.create({ mcpServers })`:
241+
The Cursor agent can use the **same MCP servers you've configured in opencode**. Forwarding is
242+
**live, per turn**: the plugin's `chat.params` hook reads opencode's current MCP state
243+
(`client.mcp.status()` for what's actually enabled right now, `client.config.get()` for the launch
244+
specs), translates each entry into the Cursor SDK's `McpServerConfig` shape, and hands the set to
245+
the agent — so enabling or disabling an MCP server mid-session takes effect on the next turn, not
246+
the next restart. A startup snapshot from the `config` hook remains as the fallback when the live
247+
read is unavailable.
242248

243249
| opencode `config.mcp` | → Cursor |
244250
| --- | --- |
245251
| `{ type: "local", command: [cmd, ...args], environment }` | `{ type: "stdio", command: cmd, args, env }` |
246252
| `{ type: "remote", url, headers }` | `{ type: "http", url, headers }` |
253+
| remote with registered OAuth client (`clientId`, optional secret/scopes) | `{ type: "http", url, auth: { CLIENT_ID, … } }` — the agent runs its own OAuth flow |
247254

248255
So whatever MCP servers your `opencode.json` defines, your Cursor agent connects to those same
249256
servers — MCP servers are independent processes, so opencode and the agent each connect to them
250257
directly.
251258
Disabled entries (`enabled: false`) are skipped. Turn this off with `forwardMcp: false`.
252259

260+
> **OAuth caveat.** opencode's own access tokens never land in `config.mcp`, so a remote server
261+
> that needs OAuth **without** a shareable `clientId` (dynamic client registration / `needs_auth`)
262+
> can't be forwarded — forwarding its spec would just 401. Such servers are skipped and a one-time
263+
> toast tells you which ones; they keep working inside opencode itself.
264+
>
265+
> **Session-reuse interaction.** A resumed Cursor agent keeps the MCP servers it was created with,
266+
> so when the forwarded set changes between turns the provider creates a fresh agent (full
267+
> transcript replay, re-pooled) instead of resuming — see
268+
> [Session reuse](#session-reuse-session). Tool definitions sit at the top of the provider's
269+
> cache-prefix hierarchy, so an MCP change also re-seeds the prompt cache.
270+
253271
> Scope note: this forwards **MCP servers**. opencode's *loop-internal* features — its own skills
254272
> and subagents — are not exposed to the Cursor agent (they run inside opencode's agent loop, which
255273
> this provider bypasses). The Cursor agent's *own* skills/rules can be loaded with the

0 commit comments

Comments
 (0)