Where does the bug appear (feature/product)?
Cursor SDK
Describe the Bug
Environment
@cursor/sdk1.0.31(currentlateston npm as of 2026-09-17)- Local runtime (
Agent.create({ local: { cwd, settingSources: ['project'] }, model, mode: 'agent' })), headless Node host, no IDE involved - Model:
claude-sonnet-5(also reproduced withgrok-4.6) - Linux (Debian) VM, not sandboxed/restricted network
Summary
A direct (depth-1) subagent, launched via the built-in task tool from a top-level Agent, does not itself get a working task tool — even though both the subagents FAQ and the TypeScript SDK docs state that “the main agent and its direct subagents can launch subagents” (only a subagent-of-a-subagent, one level further, should be blocked).
What we actually observe is stricter than documented: the direct, depth-1 subagent itself never gets a working subagent-launch mechanism at all.
Root cause (confirmed via raw on-disk transcript, not model self-report)
We have two custom subagents defined in .cursor/agents/: an orchestrator (reviewer) that’s supposed to fan out to four specialist subagents (api-checker, api-auditor, etc.) via the task tool.
- Top-level agent’s own tool-call log shows a plain, native
tasktool call ("name": "task") launchingreviewer. This works exactly as documented. reviewer’s own raw transcript (found at~/.cursor/projects/<worktree-hash>/agent-transcripts/<parentAgentId>/subagents/<subagentId>.jsonlin the on-disk local agent store), for its own attempt to launchapi-checker, shows this tool call instead:
{
"type": "tool_use",
"name": "CallDynamicTool",
"input": {
"namespace": "cursor",
"toolName": "Task",
"arguments": {
"description": "API review",
"subagent_type": "api-checker",
"prompt": "Review this GitHub PR diff for API standards."
}
}
}
That’s the MCP-style dynamic-tool bridge (GetDynamicTools/CallDynamicTool, with a reserved cursor namespace for first-party utilities) — a completely different mechanism from the native task tool the top-level agent used successfully one level up. The call was rejected; the subagent’s own final report states (closely paraphrasing what was almost certainly a real, verbatim tool error it received): “Built-in tool ‘Task’ not found in namespace ‘cursor’… available tool is only GenerateImage.”
Earlier in the same transcript, the subagent also called GetDynamicTools({ pattern: "Task" }) and GetDynamicTools({}) (full catalog) while trying to figure out how to reach a specialist subagent — again, the MCP dynamic-tools discovery mechanism, not the native tool list.
So the nested subagent isn’t being denied task access by a deliberate policy — it’s handed an entirely different, and apparently incomplete, tool schema than the top-level agent gets: an IDE-agent-style surface (Shell, Read, Glob, Grep, GetDynamicTools, CallDynamicTool) with no real subagent-launching capability registered anywhere in it, instead of the plain SDK-native toolset (lowercase tool names, including a directly-callable task) that the docs describe and that the top-level agent actually has.
Actual behavior
orchestrator has no working subagent-launch mechanism at all — not even the depth-1→2 hop the docs say should work.
Impact
This breaks any orchestrator-style subagent pattern (a subagent whose whole job is to fan out to other subagents) whenever it’s invoked as a subagent itself rather than run at the top level. Workaround we’re using in the meantime: only fan out from true depth 0 (i.e. tell the top-level agent to directly follow the orchestrator’s own instructions inline, rather than “use the X subagent”), and have the orchestrator subagent gracefully self-apply its sub-checklists (with disclosure) when it detects it has no task access — but this loses per-specialist context isolation and real parallelism, which is the whole point of the pattern.
Questions for the Cursor team
- Is this a known regression in how nested subagent tool manifests are constructed for the local SDK runtime specifically, or does it also affect the IDE/interactive product?
- Is there an SDK option (something like
local.allowNestedTaskToolor similar) to opt a subagent into the native toolset instead of the IDE-agent-style dynamic-tools surface? - Should
CallDynamicTool({ namespace: "cursor", toolName: "Task" })ever be expected to work as atask-tool equivalent, or is that purely a model hallucination of a plausible-looking tool path that happens not to exist? (If the latter, it’d be good if the nested subagent’s tool list simply included a realtaskentry so the model doesn’t need to guess.)
Happy to share full raw transcripts (redacted) if useful.
Steps to Reproduce
- Define two subagents in
.cursor/agents/:orchestrator.md(whose job is totask()-launchworker.md) andworker.md(trivial). Agent.create({ local: {...}, model, mode: 'agent' })at the top level.- Send a message instructing the top-level agent to “use the orchestrator subagent.”
- Inspect the on-disk local agent store for
orchestrator’s own subagent transcript (.cursor/projects/<hash>/agent-transcripts/<parentId>/subagents/<subagentId>.jsonl). - Observe:
orchestratorcannot find or successfully call a nativetasktool; it either doesn’t attempt a nested launch at all, or (as here) discoversCallDynamicTool/GetDynamicToolsand gets a “not found” error trying to route aTaskcall through them.
Expected Behavior
orchestrator, as a direct/depth-1 subagent, should have a working task tool and be able to launch worker as a depth-2 subagent.
Operating System
Linux
Version Information
@cursor/sdk 1.0.31 (current latest on npm as of 2026-09-17)
Does this stop you from using Cursor
Yes - Cursor is unusable