authorgravatar for aravhawk@gmail.comArav Jain <aravhawk@gmail.com> 2026-10-11 12:05:19-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-10-11 10:05:19-07:00
logc09c235129c1581f92a4f6e30470461cf7777f05
treef2fc19318ee9205b1239054b346f5adebeacb2bd
parent2625327090115a630d97ff61257758c577589de7
signature Signed by PGP key B5690EEEBB952194

fix(server): preserve ambient Cursor MCP servers (#15875)

Co-authored-by: Julius Marminge <julius0216@outlook.com>

2 files changed, 15 insertions(+), 1 deletions(-)

packages/provider-cursor/src/server/adapter.test.ts+14
...@@ -55,6 +55,17 @@ describe("CursorAdapterV2", () => {...@@ -55,6 +55,17 @@ describe("CursorAdapterV2", () => {
55 });55 });
56 const instanceId = ProviderInstanceId.make("cursor");56 const instanceId = ProviderInstanceId.make("cursor");
57 const threadId = ThreadId.make("cursor-lifecycle-thread");57 const threadId = ThreadId.make("cursor-lifecycle-thread");
58 const mcpSessions = yield* McpProviderSessions.McpProviderSessions;
59 yield* mcpSessions.set({
60 environmentId: EnvironmentId.make("cursor-lifecycle-environment"),
61 threadId,
62 providerSessionId: "cursor-lifecycle-session",
63 providerInstanceId: instanceId,
64 endpoint: "http://127.0.0.1:43123/mcp",
65 authorizationHeader: "Bearer synthetic-cursor-token",
66 browserToolsAvailable: true,
67 });
68 let sentWithMcpOverride = true;
58 const modelSelection = { instanceId, model: "composer-2.5" };69 const modelSelection = { instanceId, model: "composer-2.5" };
59 const runtimePolicy = ProviderAdapter.ProviderAdapterV2RuntimePolicy.make({70 const runtimePolicy = ProviderAdapter.ProviderAdapterV2RuntimePolicy.make({
60 runtimeMode: "full-access",71 runtimeMode: "full-access",
...@@ -75,6 +86,7 @@ describe("CursorAdapterV2", () => {...@@ -75,6 +86,7 @@ describe("CursorAdapterV2", () => {
75 close: Effect.void,86 close: Effect.void,
76 send: (input) =>87 send: (input) =>
77 Effect.gen(function* () {88 Effect.gen(function* () {
89 sentWithMcpOverride = Object.hasOwn(input.options ?? {}, "mcpServers");
78 // Recorded Cursor task calls (see fixtures/subagent) stream a90 // Recorded Cursor task calls (see fixtures/subagent) stream a
79 // partial-tool-call before tool-call-started with the same args.91 // partial-tool-call before tool-call-started with the same args.
80 // The run then ends without tool-call-completed, which a live92 // The run then ends without tool-call-completed, which a live
...@@ -184,6 +196,8 @@ describe("CursorAdapterV2", () => {...@@ -184,6 +196,8 @@ describe("CursorAdapterV2", () => {
184 Stream.takeUntil((event) => event.type === "turn.terminal"),196 Stream.takeUntil((event) => event.type === "turn.terminal"),
185 Stream.runCollect,197 Stream.runCollect,
186 );198 );
199 // Keep injected MCP at agent creation so sends preserve Cursor's ambient servers.
200 assert.isFalse(sentWithMcpOverride);
187 const rows = events.filter((event) => event.type === "subagent.updated");201 const rows = events.filter((event) => event.type === "subagent.updated");
188 assert.equal(rows[0]?.subagent.status, "running");202 assert.equal(rows[0]?.subagent.status, "running");
189 assert.equal(rows[0]?.subagent.model, model ?? null);203 assert.equal(rows[0]?.subagent.model, model ?? null);
packages/provider-cursor/src/server/adapter.ts+1-1
...@@ -2206,12 +2206,12 @@ export const makeCursorAdapterV2 = Effect.fn("makeCursorAdapterV2")(function* (...@@ -2206,12 +2206,12 @@ export const makeCursorAdapterV2 = Effect.fn("makeCursorAdapterV2")(function* (
2206 const message = yield* resolveUserMessage(turnInput, mcpServers);2206 const message = yield* resolveUserMessage(turnInput, mcpServers);
2207 const pendingUpdates: Array<InteractionUpdate> = [];2207 const pendingUpdates: Array<InteractionUpdate> = [];
2208 let context: ActiveCursorTurn | null = null;2208 let context: ActiveCursorTurn | null = null;
2209 // MCP send overrides replace the ambient servers loaded when the agent opens.
2209 const sdkRun = yield* agent.session.send({2210 const sdkRun = yield* agent.session.send({
2210 message,2211 message,
2211 options: {2212 options: {
2212 model: cursorSdkModelSelection(turnInput.modelSelection),2213 model: cursorSdkModelSelection(turnInput.modelSelection),
2213 mode: turnInput.runtimePolicy.interactionMode === "plan" ? "plan" : "agent",2214 mode: turnInput.runtimePolicy.interactionMode === "plan" ? "plan" : "agent",
2214 ...(mcpServers === undefined ? {} : { mcpServers }),
2215 },2215 },
2216 onDelta: (update) => {2216 onDelta: (update) => {
2217 if (context === null) {2217 if (context === null) {