diff --git a/apps/backend/internal/agent/agents/cursor_acp.go b/apps/backend/internal/agent/agents/cursor_acp.go index 706a69d83c..314e71bb76 100644 --- a/apps/backend/internal/agent/agents/cursor_acp.go +++ b/apps/backend/internal/agent/agents/cursor_acp.go @@ -60,8 +60,8 @@ func NewCursorACP() *CursorACP { ModelFlag: NewParam("--model", "{model}"), IdleTimeout: 3 * time.Second, BufferMaxBytes: DefaultBufferMaxBytes, - // cursor-agent has no MCP flag/env; write a project-local - // .cursor/mcp.json into the worktree (only if absent). + // cursor-agent has no MCP flag/env; write or merge a + // project-local .cursor/mcp.json into the worktree. MCPStrategy: mcpconfig.CursorStrategy{}, }, }, @@ -105,12 +105,13 @@ func (a *CursorACP) BuildCommand(opts CommandOptions) Command { func (a *CursorACP) Runtime() *RuntimeConfig { canRecover := true return &RuntimeConfig{ - Cmd: Cmd(cursorACPBin, "acp").Build(), - WorkingDir: "{workspace}", - Env: map[string]string{}, - ResourceLimits: ResourceLimits{MemoryMB: 4096, CPUCores: 2.0, Timeout: time.Hour}, - Protocol: agent.ProtocolACP, - UserSkillDir: ".cursor/skills", + Cmd: Cmd(cursorACPBin, "acp").Build(), + WorkingDir: "{workspace}", + Env: map[string]string{}, + ResourceLimits: ResourceLimits{MemoryMB: 4096, CPUCores: 2.0, Timeout: time.Hour}, + Protocol: agent.ProtocolACP, + UserSkillDir: ".cursor/skills", + ProjectMCPStrategy: mcpconfig.CursorStrategy{}, SessionConfig: SessionConfig{ NativeSessionResume: true, CanRecover: &canRecover, diff --git a/apps/backend/internal/agent/runtime/lifecycle/manager_project_mcp_test.go b/apps/backend/internal/agent/runtime/lifecycle/manager_project_mcp_test.go index 70c8c88c77..867d783008 100644 --- a/apps/backend/internal/agent/runtime/lifecycle/manager_project_mcp_test.go +++ b/apps/backend/internal/agent/runtime/lifecycle/manager_project_mcp_test.go @@ -50,6 +50,44 @@ func TestMaterializeRuntimeProjectMCPForPiWritesProjectFile(t *testing.T) { } } +func TestMaterializeRuntimeProjectMCPForCursorWritesProjectFile(t *testing.T) { + mgr := newTestManager(t) + execution := &AgentExecution{ + ID: "exec-1", + TaskID: "task-1", + SessionID: "session-1", + AgentProfileID: "profile-1", + WorkspacePath: t.TempDir(), + Metadata: map[string]interface{}{}, + standalonePort: 45678, + } + agentConfig, ok := mgr.registry.Get("cursor-acp") + if !ok { + t.Fatal("cursor-acp agent missing from test registry") + } + + if err := mgr.materializeRuntimeProjectMCP(context.Background(), execution, agentConfig); err != nil { + t.Fatalf("materializeRuntimeProjectMCP: %v", err) + } + + data, err := os.ReadFile(filepath.Join(execution.WorkspacePath, ".cursor", "mcp.json")) + if err != nil { + t.Fatalf("cursor mcp.json not written: %v", err) + } + var payload struct { + MCPServers map[string]struct { + URL string `json:"url"` + } `json:"mcpServers"` + } + if err := json.Unmarshal(data, &payload); err != nil { + t.Fatalf("cursor mcp.json not valid JSON: %v\n%s", err, data) + } + kandev := payload.MCPServers[kandevMCPServerName] + if kandev.URL != "http://localhost:45678/mcp" { + t.Fatalf("kandev URL = %q", kandev.URL) + } +} + func TestMaterializeRuntimeProjectMCPSkipsWhenPortUnavailable(t *testing.T) { mgr := newTestManager(t) execution := &AgentExecution{