Skip to content

[Bug]: Cursor threads lose all user, plugin, and project MCP servers because mcpServers is passed on every send #15268

Description

@aashish2057

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/server

Steps to reproduce

  1. Configure a remote MCP server for Cursor, for example in ~/.cursor/mcp.json ({"mcpServers":{"datadog":{"url":"https://mcp.us3.datadoghq.com/api/unstable/mcp-server/mcp"}}}). Authenticate it for the project folder, so ~/.cursor/projects/<slug>/mcp-auth.json has tokens.
  2. Start a Cursor thread in T3 Code for that project.
  3. Ask the agent to call GetDynamicTools and list the namespaces.

Direct SDK repro, without T3, using the bundled @cursor/sdk 1.0.31 and T3's settingSources. One agent sends twice:

const inline = { "probe-inline": { type: "http", url: "http://127.0.0.1:9/mcp" } };
const agent = await Agent.create({
  apiKey, model: { id: "composer-2.5" }, mode: "agent",
  local: { cwd, settingSources: ["project", "user", "team", "mdm", "plugins"],
           sandboxOptions: { enabled: false }, autoReview: false, enableAgentRetries: true },
  mcpServers: inline,
});
await (await agent.send(PROMPT)).wait();                          // send 1
await (await agent.send(PROMPT, { mcpServers: inline })).wait();  // send 2: what T3 does

Expected behavior

Cursor threads see the user, plugin, and project MCP servers loaded through settingSources, plus the t3-code server. #13499 enabled these layers so that project and user .cursor/mcp.json servers would start.

Actual behavior

Only cursor and t3-code appear. Every server from ~/.cursor/mcp.json, plugins, and project .cursor/mcp.json is missing. No error or needsAuth status is shown.

Direct SDK repro output:

=== SEND 1: mcpServers on Agent.create only ===
cursor
datadog ready
plugin-datadog-datadog error
plugin-slack-slack error
probe-inline error
slack error
=== SEND 2: same mcpServers also passed to agent.send ===
cursor
probe-inline error

(The error entries are unrelated: those servers are not authenticated or configured on this machine.)

Cause. CursorAdapterV2.ts passes mcpServers in two places:

  • makeCursorAgentOptions → Agent.create (L304–326). The SDK merges these with the workspace servers.
  • agent.session.send({ options: { mcpServers } }) on every turn (L2183–2191).

In @cursor/sdk 1.0.31, send-level mcpServers becomes mcpServersOverride for the run. The local session runtime then picks sessionLease ?? workspaceLease, where the session lease holds the inline servers only (includeUserMcp: false, includeProjectMcp: false, includePluginMcp: false). So the override replaces the workspace lease instead of adding to it, and every ambient server is dropped.

Possible fix. Stop passing mcpServers on send, and keep t3-code on Agent.create. The per-thread t3-code authorization header then has to stay current through the agent options. Alternatively, Cursor could change the SDK to merge send-level mcpServers with the workspace lease.

Impact

Major degradation or frequent failure

Version or commit

T3 Code 0.0.46-nightly.20261003.2632 (desktop). Code is unchanged on main @ 77823bd.

Environment

macOS (darwin 27.0.0), T3 Code Nightly desktop, Cursor provider (Cursor V2 / @cursor/sdk 1.0.31, cursor-agent-sdk.local), model claude-opus-5-5. Remote OAuth MCP servers: Datadog, Notion, Slack, Atlassian.

Logs or stack traces

# Provider log, agent.open for an affected thread (settingSources are correct):
"local":{"hasCwd":true,"autoReview":false,"settingSources":["project","user","team","mdm","plugins"],"sandboxEnabled":false,"enableAgentRetries":true}
# Across all provider logs, every MCP tool call uses providerIdentifier "t3-code". No other server is ever reachable.

Workaround

None in T3. Running the same SDK directly without send-level mcpServers loads the servers correctly.


Investigated with an AI coding agent (Claude Opus 5.5 in T3 Code). The repro output above comes from real runs on the reporter's machine.

Activity

  1. juliusmarminge commented on Oct 3, 2026

    @juliusmarminge
    Member

    Note

    Grok responding on behalf of Julius.

    Triage

    Thanks @aashish2057 for the clear write-up and the SDK digging. I confirmed this on main (77823bd102). It's a bug in the Cursor provider, not a missing settingSources setup, and I didn't find a duplicate.

    What's happening

    • Merged fix(server): Cursor V2 threads load project skills and rules #13499 still does the right thing when the agent opens. makeCursorAgentOptions sets settingSources to project, user, team, mdm, and plugins, and puts the thread's t3-code server on Agent.create / Agent.resume.
    • The servers get dropped by the second copy. startTurn passes the same mcpServers map into agent.session.send whenever a t3-code credential exists (CursorAdapterV2.ts, the send options next to cursorMcpServers(turnInput.threadId)).
    • @cursor/sdk 1.0.31 forwards that field as mcpServersOverride. The local runtime then builds a session lease with project, user, and plugin MCP all turned off and only those inline servers, and uses it instead of the workspace lease. The servers from create time aren't merged back in. (The t.mcpServers ?? this.options.mcpServers fallback only feeds the mcp_server_count metric.)
    • So a normal T3 turn matches the "send 2" case in your report: only cursor and t3-code remain. Threads that never inject t3-code leave mcpServers off the send, so they aren't affected.

    Likely fix area

    The send options in CursorAdapterV2.ts and how prepareMcpSession delivers credentials. Some options:

    • Leave mcpServers off send, so the workspace lease (ambient servers plus the t3-code config from create/resume) stays in effect.
    • That isn't quite a one-line deletion. prepareMcpSession reuses the bearer until browser or device access changes, then rotates it, and the send-level mcpServers is currently what pushes the new header into an agent that openAgent keeps open. A credential change would need another way onto the agent, for example re-applying create/resume options.

    A maintainer will decide on the fix direction.

  2. added
    bugSomething is broken or behaving incorrectly.
    via-triageFiled through npx t3 triage
    on Oct 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething is broken or behaving incorrectly.via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions