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", () => {
5555 });
5656 const instanceId = ProviderInstanceId.make("cursor");
5757 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;
5869 const modelSelection = { instanceId, model: "composer-2.5" };
5970 const runtimePolicy = ProviderAdapter.ProviderAdapterV2RuntimePolicy.make({
6071 runtimeMode: "full-access",
......@@ -75,6 +86,7 @@ describe("CursorAdapterV2", () => {
7586 close: Effect.void,
7687 send: (input) =>
7788 Effect.gen(function* () {
89 sentWithMcpOverride = Object.hasOwn(input.options ?? {}, "mcpServers");
7890 // Recorded Cursor task calls (see fixtures/subagent) stream a
7991 // partial-tool-call before tool-call-started with the same args.
8092 // The run then ends without tool-call-completed, which a live
......@@ -184,6 +196,8 @@ describe("CursorAdapterV2", () => {
184196 Stream.takeUntil((event) => event.type === "turn.terminal"),
185197 Stream.runCollect,
186198 );
199 // Keep injected MCP at agent creation so sends preserve Cursor's ambient servers.
200 assert.isFalse(sentWithMcpOverride);
187201 const rows = events.filter((event) => event.type === "subagent.updated");
188202 assert.equal(rows[0]?.subagent.status, "running");
189203 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* (
22062206 const message = yield* resolveUserMessage(turnInput, mcpServers);
22072207 const pendingUpdates: Array<InteractionUpdate> = [];
22082208 let context: ActiveCursorTurn | null = null;
2209 // MCP send overrides replace the ambient servers loaded when the agent opens.
22092210 const sdkRun = yield* agent.session.send({
22102211 message,
22112212 options: {
22122213 model: cursorSdkModelSelection(turnInput.modelSelection),
22132214 mode: turnInput.runtimePolicy.interactionMode === "plan" ? "plan" : "agent",
2214 ...(mcpServers === undefined ? {} : { mcpServers }),
22152215 },
22162216 onDelta: (update) => {
22172217 if (context === null) {