diff --git a/backend/Services/NexusMcpTools.cs b/backend/Services/NexusMcpTools.cs
index 28dd484..bd033cd 100644
--- a/backend/Services/NexusMcpTools.cs
+++ b/backend/Services/NexusMcpTools.cs
@@ -61,15 +61,24 @@ public sealed class NexusMcpTools(
return activity.Select(entry => new ActivityEntryDto(entry.Id, entry.Type, entry.Message, entry.CreatedAt)).ToList();
}
- // ── P1c: Mutating MCP Tools ──
+ // ── P1c: Mutating MCP Tools (TaskBridgeService facade) ──
+ //
+ // Each tool delegates directly to ITaskBridgeService without introducing
+ // new business logic. Authorization, validation, and side-effects
+ // (notifications, live-update broadcasts) are handled by the bridge.
+ ///
+ /// Creates a top-level task on the Nexus board.
+ /// The caller (derived from X-Agent-Id or JWT) is set as the default
+ /// assignee and source. Priority defaults to "Normal".
+ ///
[McpServerTool(Name = "nexus_create_task")]
[Description("Create a top-level Nexus task.")]
public async Task> CreateTask(
- string title,
- string? detail = null,
- string? priority = "Normal",
- string? assignedTo = null,
+ [Description("Task title (required).")] string title,
+ [Description("Optional long-form description.")] string? detail = null,
+ [Description("Priority label. Defaults to 'Normal'.")] string? priority = "Normal",
+ [Description("Agent ID to assign the task to. Defaults to the caller.")] string? assignedTo = null,
CancellationToken ct = default)
{
var caller = await ResolveCallerAsync(ct);
@@ -84,16 +93,21 @@ public sealed class NexusMcpTools(
return ToResponse(result, "nexus_create_task");
}
+ ///
+ /// Creates a visible child task under a Nexus parent for delegation.
+ /// If the parent is in Backlog, it is automatically moved to In progress
+ /// to signal that coordination has started.
+ ///
[McpServerTool(Name = "nexus_create_child_task")]
[Description("Create a visible child task under a Nexus parent task for delegation.")]
public async Task> CreateChildTask(
- Guid parentTaskId,
- string title,
- string? detail = null,
- string? priority = "Normal",
- string? assignedTo = null,
- string? expectedFrom = null,
- bool startsInProgress = false,
+ [Description("ID of the parent task.")] Guid parentTaskId,
+ [Description("Child task title (required).")] string title,
+ [Description("Optional long-form description.")] string? detail = null,
+ [Description("Priority label. Defaults to 'Normal'.")] string? priority = "Normal",
+ [Description("Agent ID to assign. Defaults to the expected-from agent.")] string? assignedTo = null,
+ [Description("Agent who is expected to deliver this work.")] string? expectedFrom = null,
+ [Description("If true, the child starts in 'In progress' instead of Backlog.")] bool startsInProgress = false,
CancellationToken ct = default)
{
var caller = await ResolveCallerAsync(ct);
@@ -111,11 +125,21 @@ public sealed class NexusMcpTools(
return ToResponse(result, "nexus_create_child_task");
}
+ ///
+ /// Updates a task's lifecycle state.
+ /// The parameter is typed as
+ /// so the MCP SDK rejects unknown
+ /// integer values before the tool is ever invoked. Additionally,
+ /// performs an exhaustive switch with a
+ /// defensive fallback.
+ /// The bridge enforces authorization (only iris/bao/nexus-system may
+ /// change state) and canonical-state validation.
+ ///
[McpServerTool(Name = "nexus_update_status")]
[Description("Update a Nexus task status. The schema only exposes canonical task states.")]
public async Task> UpdateStatus(
- Guid taskId,
- NexusMcpTaskState state,
+ [Description("ID of the task to update.")] Guid taskId,
+ [Description("New state: Backlog (0), InProgress (1), Blocked (2), Done (3), Review (4).")] NexusMcpTaskState state,
CancellationToken ct = default)
{
var caller = await ResolveCallerAsync(ct);
@@ -123,12 +147,16 @@ public sealed class NexusMcpTools(
return ToResponse(result, "nexus_update_status");
}
+ ///
+ /// Appends an activity entry (comment, status note, or checkpoint) to a task.
+ /// This triggers a live-update broadcast so dashboards stay current.
+ ///
[McpServerTool(Name = "nexus_append_activity")]
[Description("Append an activity/checkpoint entry to a Nexus task.")]
public async Task> AppendActivity(
- Guid taskId,
- string message,
- string? type = "comment",
+ [Description("ID of the task to annotate.")] Guid taskId,
+ [Description("Activity message text (required).")] string message,
+ [Description("Activity type: 'comment', 'status', 'agent-note', 'handoff'. Defaults to 'comment'.")] string? type = "comment",
CancellationToken ct = default)
{
await ResolveCallerAsync(ct);
@@ -136,12 +164,17 @@ public sealed class NexusMcpTools(
return ToActivityResponse(result, "nexus_append_activity");
}
+ ///
+ /// Marks a task handoff to another agent.
+ /// Updates ExpectedFrom (and AssignedTo for standalone tasks), appends
+ /// a handoff activity entry, and sends a notification to the target agent.
+ ///
[McpServerTool(Name = "nexus_handoff")]
[Description("Mark a task handoff to another known agent and append handoff activity.")]
public async Task> Handoff(
- Guid taskId,
- string targetAgent,
- string? note = null,
+ [Description("ID of the task to hand off.")] Guid taskId,
+ [Description("Target agent ID (must be a known agent).")] string targetAgent,
+ [Description("Optional handoff note.")] string? note = null,
CancellationToken ct = default)
{
await ResolveCallerAsync(ct);
@@ -226,11 +259,38 @@ public sealed class NexusMcpTools(
};
}
+///
+/// Canonical task states exposed via the MCP tool schema.
+/// Integer values 0-4 map to the canonical string representations used
+/// by . The MCP SDK rejects
+/// out-of-range integers before the tool is invoked.
+///
public enum NexusMcpTaskState
{
- Backlog,
- InProgress,
- Blocked,
- Done,
- Review
+ /// Task is in the backlog (not yet started).
+ Backlog = 0,
+ /// Work is actively in progress.
+ InProgress = 1,
+ /// Work is blocked by an external dependency.
+ Blocked = 2,
+ /// Work is complete.
+ Done = 3,
+ /// Work is ready for review.
+ Review = 4
+}
+
+///
+/// Static helpers for .
+/// The method provides a testable entry point
+/// for verifying that update_status rejects invalid state values.
+///
+public static class NexusMcpTaskStateHelper
+{
+ ///
+ /// Returns true when is one of the five
+ /// canonical values defined in .
+ /// Rejects undefined cast values (e.g. (NexusMcpTaskState)99).
+ ///
+ public static bool IsDefined(NexusMcpTaskState state) =>
+ Enum.IsDefined(state);
}