refactor(mcp): drop task-document tools from kanban mode (#1014)

This commit is contained in:
Carlos Florêncio
2026-05-22 16:24:23 +01:00
committed by GitHub
parent a2b4fc0c6d
commit 2bcda51968
3 changed files with 40 additions and 19 deletions
@@ -9,24 +9,31 @@ import (
"github.com/mark3labs/mcp-go/server"
)
// registerHandoffTools registers the office task-handoff MCP tools:
// list_related_tasks_kandev, list_task_documents_kandev,
// get_task_document_kandev, write_task_document_kandev. These are
// available in ModeOffice and ModeTask so both office coordinators and
// task assignees can read parent / sibling documents and write
// child→parent coordination docs.
func (s *Server) registerHandoffTools() {
// registerRelatedTasksTool registers list_related_tasks_kandev, which lets an
// agent discover parent / child / sibling / blocker task IDs. Useful in both
// kanban (ModeTask) and office (ModeOffice) modes — kanban agents commonly use
// it to find a sibling task to send a follow-up to via message_task_kandev.
func (s *Server) registerRelatedTasksTool() {
s.mcpServer.AddTool(
mcp.NewTool("list_related_tasks_kandev",
mcp.WithDescription(
`List parent, children, siblings, blockers, and blocked tasks for the current task.
Use this to discover task IDs you can read documents from. Document keys are included so you can pick
the document to fetch with get_task_document_kandev. Pass task_id to inspect a different task in the same workspace.`,
Use this to discover task IDs you can reach via message_task_kandev. In office mode, document keys are
also included so you can fetch documents with get_task_document_kandev.
Pass task_id to inspect a different task in the same workspace.`,
),
mcp.WithString("task_id", mcp.Description("Defaults to the current task.")),
),
s.wrapHandler("list_related_tasks_kandev", s.listRelatedTasksHandler()),
)
}
// registerTaskDocumentTools registers the cross-task document tools used for
// office parent/child coordination: list_task_documents_kandev,
// get_task_document_kandev, write_task_document_kandev. These are office-only
// — kanban tasks don't use the document handoff pattern, so the surface is
// kept lean.
func (s *Server) registerTaskDocumentTools() {
s.mcpServer.AddTool(
mcp.NewTool("list_task_documents_kandev",
mcp.WithDescription(
+11 -5
View File
@@ -314,7 +314,8 @@ func (s *Server) registerTools() {
// surface for office mode only keeps:
// - ask_user_question — interactive prompt path
// - plan tools — structured plan capture
// - handoff tools — workflow handoff between steps
// - related-tasks — discover parent/child/sibling IDs
// - task-document tools — parent/child coordination docs
// delegate_task was removed in favour of
// `agentctl kandev tasks create --parent $KANDEV_TASK_ID …`.
if !s.disableAskQuestion {
@@ -323,9 +324,14 @@ func (s *Server) registerTools() {
}
s.registerPlanTools()
count += 4
s.registerHandoffTools()
count += 4
s.registerRelatedTasksTool()
count++
s.registerTaskDocumentTools()
count += 3
default: // ModeTask
// Kanban tasks get list_related_tasks_kandev (useful for finding
// a sibling to message_task_kandev) but NOT the task-document
// tools — those are office coordination plumbing.
s.registerKanbanTools()
count += 11
if !s.disableAskQuestion {
@@ -334,8 +340,8 @@ func (s *Server) registerTools() {
}
s.registerPlanTools()
count += 4
s.registerHandoffTools()
count += 4
s.registerRelatedTasksTool()
count++
}
s.logger.Info("registered MCP tools",
zap.String("mode", s.mode),
@@ -59,6 +59,13 @@ func TestServerModeTask_RegistersCorrectTools(t *testing.T) {
assert.Contains(t, tools, "list_agents_kandev")
assert.Contains(t, tools, "list_executor_profiles_kandev")
// Task mode keeps list_related_tasks_kandev (sibling discovery) but
// drops the task-document tools — those are office-only.
assert.Contains(t, tools, "list_related_tasks_kandev")
assert.NotContains(t, tools, "list_task_documents_kandev")
assert.NotContains(t, tools, "get_task_document_kandev")
assert.NotContains(t, tools, "write_task_document_kandev")
// Task mode should NOT have config/mutation tools
assert.NotContains(t, tools, "create_workflow_kandev")
assert.NotContains(t, tools, "update_workflow_kandev")
@@ -197,8 +204,9 @@ func TestServerModeTask_ToolCount(t *testing.T) {
s := New(backend, "test-session", "test-task", 10005, log, "", false, ModeTask)
tools := getRegisteredToolNames(s)
// 11 kanban + 1 interaction + 4 plan + 4 handoff = 20
assert.Equal(t, 20, len(tools))
// 11 kanban + 1 interaction + 4 plan + 1 related-tasks = 17.
// Task-document tools (list/get/write) are office-only.
assert.Equal(t, 17, len(tools))
}
func TestServerModeConfig_ToolCount(t *testing.T) {
@@ -279,8 +287,8 @@ func TestServerModeOffice_ToolCount(t *testing.T) {
s := New(backend, "test-session", "test-task", 10005, log, "", false, ModeOffice)
tools := getRegisteredToolNames(s)
// 4 plan + 1 interaction + 4 handoff = 9 (delegate_task_kandev
// retired in favour of `agentctl kandev task create …`).
// 4 plan + 1 interaction + 1 related-tasks + 3 task-documents = 9
// (delegate_task_kandev retired in favour of `agentctl kandev task create …`).
assert.Equal(t, 9, len(tools))
}
@@ -298,7 +306,7 @@ func TestServerModeOffice_DisableAskQuestion(t *testing.T) {
// delegate_task_kandev was retired from ModeOffice (now lives in
// the agentctl CLI as `agentctl kandev task create --parent …`).
assert.NotContains(t, tools, "delegate_task_kandev")
// 4 plan + 4 handoff = 8 (no ask_user_question, no delegate)
// 4 plan + 1 related-tasks + 3 task-documents = 8 (no ask_user_question, no delegate)
assert.Equal(t, 8, len(tools))
}