Skip to content

Implement user-directed MCP task mutation tools - #30

Merged
krishna916 merged 4 commits into
mainfrom
feature/issue-21-mcp-mutations
Jul 27, 2026
Merged

Implement user-directed MCP task mutation tools#30
krishna916 merged 4 commits into
mainfrom
feature/issue-21-mcp-mutations

Conversation

@krishna916

@krishna916 krishna916 commented Jul 27, 2026

Copy link
Copy Markdown
Owner

Summary

Implements issue #21's five intent-specific MCP mutation tools:

  • task_edit
  • task_triage
  • task_start
  • task_complete
  • task_archive

The handlers reuse the shared MCP envelopes, schemas, DTO mapping, error mapping, and focused task-application operations. Mutation results include deterministic change metadata and safe no-op handling. No generic mutation path or SQLite access is introduced.

Validation

  • tsc --build --noEmit
  • 38 targeted application/MCP/stdio tests

pnpm verify remains blocked by pre-existing formatting violations in unrelated files; all files in this change pass Prettier checks.

Summary by CodeRabbit

  • New Features
    • Added MCP task mutation tools: edit, triage, start, complete, and archive.
    • Mutation responses now include structured results with before/after task data and explicit change metadata.
    • Support for clearing editable fields via tool inputs.
  • Bug Fixes
    • Improved input validation with clearer MCP invalid-parameter behavior.
    • Added more accurate error codes for conflicts and archived-task scenarios, avoiding internal error details.
    • No-op/idempotent actions now return NO_CHANGE consistently without unintended persistence effects.
  • Documentation
    • Updated MCP mutation contract documentation to reflect the revised schemas, lifecycle behavior, and error mappings.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ec4eef3b-4769-456f-8058-8c9f79b2469d

📥 Commits

Reviewing files that changed from the base of the PR and between 6f9a583 and 3b6ce3f.

📒 Files selected for processing (8)
  • src/interfaces/contracts/task-contract.ts
  • src/interfaces/mcp/tools/task-complete.ts
  • src/interfaces/mcp/tools/task-edit.ts
  • src/interfaces/mcp/tools/task-start.ts
  • tests/unit/interfaces/contracts/agent-integration-contracts.test.ts
  • tests/unit/interfaces/mcp/create-mcp-server.test.ts
  • tests/unit/interfaces/mcp/mcp-test-utils.ts
  • tests/unit/interfaces/mcp/mutation-tool-handlers.test.ts
🚧 Files skipped from review as they are similar to previous changes (6)
  • src/interfaces/mcp/tools/task-start.ts
  • src/interfaces/mcp/tools/task-complete.ts
  • src/interfaces/mcp/tools/task-edit.ts
  • src/interfaces/contracts/task-contract.ts
  • tests/unit/interfaces/mcp/create-mcp-server.test.ts
  • tests/unit/interfaces/mcp/mutation-tool-handlers.test.ts

📝 Walkthrough

Walkthrough

Adds five intent-specific MCP task mutation tools with strict schemas, structured change metadata, before/after application results, error mapping, server registration, documentation, and unit/integration coverage.

Changes

MCP mutation workflow

Layer / File(s) Summary
Mutation contracts and application results
src/application/tasks/..., src/interfaces/contracts/..., src/interfaces/mcp/schemas/..., src/interfaces/http/task-routes.ts
Task mutations now return { before, task }; MCP schemas define structured edit and triage metadata, and HTTP/read schemas consume the updated result shape.
MCP mutation registration and execution
src/interfaces/mcp/tools/..., src/interfaces/mcp/mapping/..., src/interfaces/mcp/create-mcp-server.ts
Registers five focused mutation tools with change mapping and domain-error translation.
Mutation behavior and protocol validation
tests/unit/..., tests/integration/mcp-stdio.test.ts, .gitignore, eslint.config.js
Tests validate discovery, strict inputs, focused application calls, no-op behavior, error redaction, and the complete MCP lifecycle workflow.
Mutation contract documentation
docs/mcp-tools.md, docs/superpowers/plans/...
Documents schema validation, mutation semantics, error ownership, safety constraints, and implementation checkpoints.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant MCPClient
  participant McpServer
  participant TaskApplication
  participant ChangeMetadata
  MCPClient->>McpServer: Invoke task mutation
  McpServer->>TaskApplication: Call focused mutation
  TaskApplication-->>McpServer: Return before and task
  McpServer->>ChangeMetadata: Compute change descriptor
  ChangeMetadata-->>McpServer: Return structured metadata
  McpServer-->>MCPClient: Return versioned result or mapped error
Loading

Possibly related issues

Possibly related PRs

  • krishna916/relay#11 — Introduces lifecycle and error types used by the new MCP mappings.
  • krishna916/relay#13 — Introduces the application services whose mutation return contracts are expanded here.
  • krishna916/relay#29 — Adds MCP server wiring extended here with mutation tool registration.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding user-directed MCP task mutation tools.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/issue-21-mcp-mutations

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@krishna916 krishna916 linked an issue Jul 27, 2026 that may be closed by this pull request
7 tasks

Copy link
Copy Markdown
Owner Author

Luna follow-up implementation plan for review fixes

Address the review findings below in order. Keep the scope limited to PR #30 and issue #21. Do not introduce CLI work, skills, vendor integrations, auth, bulk mutation, restore/reopen, permanent deletion, or persistence redesign.

Goal

Bring PR #30 fully in line with issue #21 by:

  1. Completing the missing mutation test matrix.
  2. Reusing one shared MCP output-envelope schema helper.
  3. Resolving or explicitly simplifying the duplicated application mutation API.
  4. Updating the PR verification evidence.

Task 1 — Complete the mutation schema test matrix

Files

Primarily:

  • tests/unit/interfaces/mcp/create-mcp-server.test.ts
  • optionally add a focused schema test file under tests/unit/interfaces/mcp/ if that keeps the server test readable

Required tests

Add explicit tests for task_edit schema behavior:

  1. Reject a call with only taskId and no editable field.
  2. Reject unknown fields.
  3. Reject all immutable or forbidden fields individually or through a parameterized test:
    • status
    • createdByType
    • createdByName
    • sessionId
    • createdAt
    • updatedAt
    • startedAt
    • completedAt
    • archivedAt
    • confirmed
    • requestedBy
  4. Reject direct MCP null for editable values where the contract requires clear flags.
  5. Reject conflicting value-plus-clear combinations:
    • description with clearDescription: true
    • priority with clearPriority: true
    • workspace with clearWorkspace: true
    • sourceContext with clearSourceContext: true
  6. Confirm task_triage accepts only:
    • INBOX
    • ACTIVE
    • BACKLOG
  7. Confirm task_triage rejects:
    • IN_PROGRESS
    • DONE
    • ARCHIVED
  8. Confirm task_start, task_complete, and task_archive reject unknown fields.
  9. Confirm malformed schema-level calls fail through SDK-native MCP invalid-params behavior rather than Relay’s structured execution-error envelope.

Guidance

  • Prefer parameterized tests for forbidden edit fields and invalid triage targets.
  • Test actual client.callTool(...) behavior where possible, not only the JSON Schema advertised by discovery.
  • Keep discovery assertions as an additional contract guard, not as the sole proof.

Acceptance criteria

  • Every forbidden and immutable mutation path is proven unreachable through MCP input validation.
  • No fake conversational authorization field is accepted.
  • No generic status mutation is possible.

Task 2 — Cover every editable field and clear operation

Files

  • tests/unit/interfaces/mcp/create-mcp-server.test.ts

Required tests

Prove successful editing of every allowed field:

  1. title
  2. description
  3. priority
  4. workspace
  5. sourceContext

Prove explicit clearing of every nullable editable field:

  1. clearDescription
  2. clearPriority
  3. clearWorkspace
  4. clearSourceContext

For each case verify:

  • the complete returned task contains the persisted value
  • change.action is EDITED
  • change.fields contains only the field that actually changed
  • the persisted task can be fetched afterward with task_get and matches the mutation result

Stable field ordering test

Add one test that changes multiple non-adjacent fields in an input order different from the contract order. Example input order:

{
  taskId,
  sourceContext: 'new context',
  title: 'new title',
  priority: 'HIGH'
}

Expected change.fields must remain:

['title', 'priority', 'sourceContext']

Do not derive ordering from object insertion order or request order.

Acceptance criteria

  • Every allowed edit operation is covered.
  • Every allowed clear operation is covered.
  • Change metadata reflects persisted differences only.
  • Field ordering is deterministic and contract-defined.

Task 3 — Complete no-op coverage

Files

  • tests/unit/interfaces/mcp/create-mcp-server.test.ts

Required tests

Add explicit successful no-op tests for:

  1. task_edit
    • setting a field to its current normalized value
    • clearing an already-null field
  2. task_triage
    • triaging INBOX -> INBOX, ACTIVE -> ACTIVE, or BACKLOG -> BACKLOG
  3. task_start
    • starting an already IN_PROGRESS task
  4. task_complete
    • completing an already DONE task
  5. task_archive
    • verify the authoritative domain behavior before writing this test

Important archive clarification

The current lifecycle implementation gives ARCHIVED no outgoing transitions and checks same-target before archived restriction. Therefore archiving an already archived task may currently return the same task as an approved no-op. Preserve the existing domain contract unless issue #19 or existing domain tests say otherwise.

For every approved no-op verify:

  • MCP result is successful, not isError
  • change.action === 'NO_CHANGE'
  • edit no-op returns fields: []
  • triage no-op returns equal from and to
  • task timestamps do not change
  • repository update is not invoked if the in-memory fixture can observe update calls

Acceptance criteria

  • All approved no-ops exit through the success path.
  • No-op metadata is deterministic.
  • No-op mutations do not perform unnecessary persistence writes.

Task 4 — Complete error mapping coverage

Files

  • tests/unit/interfaces/mcp/create-mcp-server.test.ts
  • test fixtures under tests/unit/application/tasks/ if required

Required execution-error tests

Cover the following Relay structured errors after valid MCP schema validation:

  1. VALIDATION_ERROR
    • use a schema-valid request that fails application/domain validation
    • do not use an unknown input field because that is SDK invalid-params behavior
  2. NOT_FOUND
    • at least one focused mutation against a missing task
  3. CONFLICT
    • invalid lifecycle transition
    • include more than one intent where useful, such as start from INBOX and triage from DONE
  4. ARCHIVED_TASK
    • archived edit
    • archived triage
    • archived start
    • archived complete
    • archived archive only if the authoritative lifecycle contract treats it as restricted rather than no-op; otherwise document and test no-op behavior
  5. STORAGE_ERROR
    • repository update failure
    • verify no internal repository message, SQL detail, path, stack, or cause leaks
  6. INTERNAL_ERROR
    • inject an unexpected non-domain exception through a controlled test double
    • verify the public message is generic
    • verify the original exception message is absent from serialized output

Guidance

Acceptance criteria


Task 5 — Verify every tool calls one focused application operation

Files

  • tests/unit/interfaces/mcp/ or a new focused registration/handler test file
  • possibly src/interfaces/mcp/tools/*.ts only if a wiring defect is found

Required tests

Use a narrow TaskApplication spy/fake to prove:

  • task_edit calls only the focused edit mutation operation
  • task_triage maps:
    • INBOX to move-to-inbox
    • ACTIVE to activate
    • BACKLOG to move-to-backlog
  • task_start calls only start
  • task_complete calls only complete
  • task_archive calls only archive

Verify handlers do not:

  • access repositories directly
  • perform a separate get followed by mutation
  • call multiple lifecycle methods
  • derive lifecycle legality in the MCP adapter

Acceptance criteria

  • Adapter responsibility remains validation, invocation, and mapping only.
  • Domain/application services remain authoritative for mutation legality.

Task 6 — Extract one shared MCP output-envelope schema helper

Current problem

src/interfaces/mcp/schemas/mutation-tool-schemas.ts duplicates the same versioned MCP output-envelope construction already present in the read/capture schema module.

Files

Suggested shape:

  • create src/interfaces/mcp/schemas/mcp-output-schema.ts
  • modify src/interfaces/mcp/schemas/read-tool-schemas.ts
  • modify src/interfaces/mcp/schemas/mutation-tool-schemas.ts
  • update tests if import paths change

Implementation

Extract one helper equivalent to:

export function createMcpOutputSchema<T extends z.ZodType>(data: T) {
  return z
    .object({
      schemaVersion: z.literal(CONTRACT_SCHEMA_VERSION),
      data,
      warnings: z.array(warningSchema),
    })
    .strict();
}

Use the repository’s TypeScript/Zod conventions and preserve useful inferred types. Do not introduce a generic schema framework beyond this one shared helper.

Constraints

  • Do not change public MCP output shapes.
  • Do not change contract schema version.
  • Do not change read/capture behavior.
  • Do not create parallel warning or envelope definitions.

Acceptance criteria

  • Read/capture and mutation outputs use exactly one envelope-schema implementation.
  • Existing contract tests continue to pass unchanged or with import-only updates.

Task 7 — Simplify the duplicated application mutation API

Current problem

TaskApplication now exposes both variants for the same operations, for example:

edit(...)
editWithPrevious(...)
start(...)
startWithPrevious(...)

This creates two application surfaces for each mutation and lets future adapters choose inconsistent methods.

Required decision

Prefer one canonical mutation contract rather than permanent method pairs.

Recommended option

Make focused mutation methods return a shared mutation result:

interface TaskMutationResult {
  readonly before: Task;
  readonly task: Task;
}

Apply this consistently to:

  • edit
  • moveToInbox
  • activate
  • moveToBacklog
  • start
  • complete
  • archive

Then update existing internal callers deliberately. Where an existing caller only needs the resulting task, use .task at that caller boundary.

Alternative allowed only with justification

Keep the current task-returning API and introduce a separate narrowly scoped mutation facade used by MCP. If this option is chosen:

  • name the boundary clearly
  • avoid duplicating business logic
  • document why both surfaces are needed
  • add tests proving both delegate to the same use cases

Constraints

  • Do not fetch the task twice merely to calculate before/after metadata.
  • Do not move change-metadata calculation into SQLite repositories.
  • Do not make the MCP adapter responsible for lifecycle logic.
  • Preserve atomic before/result capture within the application operation.
  • Avoid a broad refactor beyond task mutation methods and their direct callers.

Likely files

  • src/application/tasks/task-application.ts
  • src/application/tasks/use-cases/edit-task.ts
  • src/application/tasks/use-cases/transition-task.ts
  • direct callers and affected tests

Acceptance criteria

  • There is one clear canonical application mutation API.
  • MCP still receives reliable before/after values without duplicate reads.
  • Existing HTTP/UI behavior remains unchanged.
  • No mutation rules are duplicated.

Task 8 — Preserve existing tools and protocol cleanliness

Files

  • tests/integration/mcp-stdio.test.ts
  • existing MCP unit tests

Required assertions

  1. Existing tools remain discoverable and unchanged:
    • task_capture
    • task_list
    • task_get
    • task_find_similar
    • session_captures_list
  2. Exactly the five approved mutation tools are present.
  3. Generic mutation tools remain absent:
    • task_update
    • task_set_status
    • unrestricted generic mutation command variants
  4. Extend the built stdio integration to perform at least:
    • capture
    • edit
    • triage or start
    • complete or archive
    • read back the final complete task
  5. Assert stdout remains MCP protocol-clean.
  6. Assert no logs, stack traces, SQL details, or debug output are written to stdout.

Acceptance criteria

  • Existing read/capture behavior has no regression.
  • Mutation works through the built stdio entry point, not merely in-memory transport.
  • Protocol output remains clean.

Task 9 — Update documentation and PR evidence

Files

Documentation checks

Ensure docs/mcp-tools.md explicitly documents:

  • exact accepted input names as implemented (taskId, target, clear flags)
  • every editable field
  • direct null rejection and clear-flag behavior
  • deterministic edit field order
  • triage target restriction
  • complete mutation result shape
  • no-op behavior
  • archived and conflict behavior
  • explicit-user-direction behavioral precondition
  • absence of fake confirmation fields
  • SDK invalid-params vs Relay structured execution-error distinction

PR description update

Replace stale validation text claiming pnpm verify is blocked. Record the final successful commands and current CI result.

Use evidence from the final head commit only.


Required implementation sequence

  1. Add failing schema and handler tests for the missing cases.
  2. Add failing no-op and error-mapping tests.
  3. Extract the shared MCP output-envelope helper.
  4. Simplify the application mutation API with the smallest safe refactor.
  5. Make implementation changes required by the tests.
  6. Extend stdio integration coverage.
  7. Update documentation.
  8. Run the complete verification suite.
  9. Update the PR description with final evidence.

Do not weaken or delete tests merely to make the suite pass.


Verification commands

Run all of the following from a clean working tree:

pnpm test -- tests/unit/interfaces/mcp
pnpm test -- tests/integration/mcp-stdio.test.ts
pnpm format:check
pnpm lint
pnpm typecheck
pnpm test:coverage
pnpm build
pnpm validate:assets
pnpm verify

Also inspect the final diff for accidental scope expansion:

git diff --stat main...HEAD
git diff main...HEAD

Final evidence required in the PR

Report:

  • final head commit SHA
  • exact commands run
  • pass/fail result for each command
  • number of unit and integration tests executed
  • confirmation that stdout protocol-cleanliness was tested
  • confirmation that no generic mutation tool exists
  • confirmation that existing read/capture tools remain unchanged

Human review checkpoints

Before marking the PR ready for re-review, manually verify:

  1. Every mutation schema rejects unknown, immutable, provenance, session, and timestamp fields.
  2. task_triage cannot reach IN_PROGRESS, DONE, or ARCHIVED.
  3. No fake conversational confirmation field exists.
  4. Every handler calls one focused application mutation operation.
  5. Before/after metadata is obtained without duplicate repository reads.
  6. All approved no-ops return success with deterministic metadata.
  7. Archived restrictions match the domain lifecycle contract.
  8. Read/capture tools and envelopes have not changed unintentionally.
  9. MCP stdout remains protocol-clean.
  10. pnpm verify passes on the final commit.

Once all items are complete, leave a concise PR comment summarizing the fixes and request re-review.

@krishna916
krishna916 marked this pull request as ready for review July 27, 2026 07:42

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (6)
src/interfaces/contracts/task-contract.ts (1)

163-187: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Encode change-metadata invariants in the result schemas.

The schemas currently accept contradictory payloads: EDITED with an empty or duplicate fields array, NO_CHANGE with changed fields, and triage NO_CHANGE/TRIAGED values inconsistent with from and to. Add discriminated unions or refinements so the MCP contract enforces the invariants already produced by editChange and triageChange.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/interfaces/contracts/task-contract.ts` around lines 163 - 187, Strengthen
taskEditResultSchema and taskTriageResultSchema with discriminated unions or
refinements that enforce change metadata: EDITED requires one or more unique
fields, while NO_CHANGE requires an empty fields array; triage NO_CHANGE
requires from and to to match, and TRIAGED requires them to differ. Preserve the
existing taskDtoSchema and strict object contracts.
src/interfaces/mcp/tools/task-start.ts (1)

18-26: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

All mutation handlers are async but call TaskApplication synchronously. The shared root cause is that each handler's try/catchtoMcpError mapping only holds while the application methods stay synchronous; if any becomes promise-returning, the rejection escapes the catch and surfaces as an unmapped SDK error instead of a structured MCP error.

  • src/interfaces/mcp/tools/task-start.ts#L18-L26: await the application.start(...) result (harmless today, future-proof) or keep the handler synchronous.
  • src/interfaces/mcp/tools/task-complete.ts#L20-L29: same change for application.complete(...).
  • src/interfaces/mcp/tools/task-edit.ts#L20-L50: same change for application.edit(...).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/interfaces/mcp/tools/task-start.ts` around lines 18 - 26, The async
mutation handlers must await application operations so promise rejections remain
within their structured error mapping. In src/interfaces/mcp/tools/task-start.ts
lines 18-26, await application.start; apply the same change to
application.complete in src/interfaces/mcp/tools/task-complete.ts lines 20-29
and application.edit in src/interfaces/mcp/tools/task-edit.ts lines 20-50,
preserving each handler’s existing toMcpError catch behavior.
tests/unit/interfaces/mcp/mutation-tool-handlers.test.ts (2)

288-289: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Rename afterEditUpdatedAt.

It's read after both the edit and the triage no-op, so the name understates what it covers.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/interfaces/mcp/mutation-tool-handlers.test.ts` around lines 288 -
289, Rename the afterEditUpdatedAt variable in the mutation-tool handler test to
reflect that its value is read after both the edit and the triage no-op, and
update the corresponding expectation reference.

40-46: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Share the hardened connect helper instead of a second, weaker copy.

create-mcp-server.test.ts has a connectMcp that guards against a failed connect (closing both sides, idempotent close, allSettled). This copy leaks the server/transport if client.connect rejects, and close will reject rather than settle if either side throws — leaving a dangling server between tests. Extracting the existing helper into a shared test util removes the divergence.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/interfaces/mcp/mutation-tool-handlers.test.ts` around lines 40 -
46, Replace the local connect helper in the mutation handler tests with the
hardened connectMcp helper from create-mcp-server.test.ts, extracting it into a
shared test utility if needed. Preserve failed-connect cleanup, idempotent close
behavior, and allSettled-based shutdown, and update callers to use the shared
helper.
tests/unit/interfaces/mcp/create-mcp-server.test.ts (1)

76-105: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Test name promises "only", but arrayContaining is a subset check.

toEqual(expect.arrayContaining([...])) passes as long as the five names are present; exclusivity rests entirely on the two hardcoded not.toContain checks at Lines 104-105. A newly added generic mutation tool would not fail this test. Consider asserting the exact tool-name set (read + capture + health + the five) so any new tool must be explicitly acknowledged.

💚 Proposed tightening
-      expect([...byName.keys()]).toEqual(
-        expect.arrayContaining([
-          'task_edit',
-          'task_triage',
-          'task_start',
-          'task_complete',
-          'task_archive',
-        ]),
-      );
+      expect([...byName.keys()].sort()).toEqual(EXPECTED_TOOL_NAMES);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/interfaces/mcp/create-mcp-server.test.ts` around lines 76 - 105,
Strengthen the tool-name assertion in the test “exposes only the five
intent-specific user-directed mutation tools” by comparing the complete set of
exposed names against the expected read, capture, health, and five
intent-specific mutation tools. Replace the subset-only arrayContaining
assertion and remove reliance on the separate task_update/task_set_status
exclusions so any newly added tool requires explicit acknowledgment.
src/interfaces/mcp/tools/task-edit.ts (1)

20-43: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Collapse the repeated clear/value ternaries into a helper.

The same four-line nested ternary is repeated for description, priority, workspace, and sourceContext. A small helper keeps the payload construction readable and makes adding a new clearable field a one-liner.

♻️ Proposed refactor
+function optionalField<T>(
+  value: T | undefined,
+  clear: boolean | undefined,
+): Record<string, T | null> | Record<string, never> {
+  if (value !== undefined) return { value } as never;
+  return clear === true ? ({ value: null } as never) : ({} as never);
+}

Or inline, keyed by field name:

-          ...(input.description === undefined
-            ? input.clearDescription === true
-              ? { description: null }
-              : {}
-            : { description: input.description }),
+          ...nullableEdit('description', input.description, input.clearDescription),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/interfaces/mcp/tools/task-edit.ts` around lines 20 - 43, Extract the
repeated clear-or-value logic from the application.edit payload in the task-edit
handler into a small reusable helper. Have it accept the field value and
corresponding clear flag, returning the field update or an empty object, then
use it for description, priority, workspace, and sourceContext while preserving
the current undefined and null-clearing behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/interfaces/contracts/task-contract.ts`:
- Around line 163-187: Strengthen taskEditResultSchema and
taskTriageResultSchema with discriminated unions or refinements that enforce
change metadata: EDITED requires one or more unique fields, while NO_CHANGE
requires an empty fields array; triage NO_CHANGE requires from and to to match,
and TRIAGED requires them to differ. Preserve the existing taskDtoSchema and
strict object contracts.

In `@src/interfaces/mcp/tools/task-edit.ts`:
- Around line 20-43: Extract the repeated clear-or-value logic from the
application.edit payload in the task-edit handler into a small reusable helper.
Have it accept the field value and corresponding clear flag, returning the field
update or an empty object, then use it for description, priority, workspace, and
sourceContext while preserving the current undefined and null-clearing behavior.

In `@src/interfaces/mcp/tools/task-start.ts`:
- Around line 18-26: The async mutation handlers must await application
operations so promise rejections remain within their structured error mapping.
In src/interfaces/mcp/tools/task-start.ts lines 18-26, await application.start;
apply the same change to application.complete in
src/interfaces/mcp/tools/task-complete.ts lines 20-29 and application.edit in
src/interfaces/mcp/tools/task-edit.ts lines 20-50, preserving each handler’s
existing toMcpError catch behavior.

In `@tests/unit/interfaces/mcp/create-mcp-server.test.ts`:
- Around line 76-105: Strengthen the tool-name assertion in the test “exposes
only the five intent-specific user-directed mutation tools” by comparing the
complete set of exposed names against the expected read, capture, health, and
five intent-specific mutation tools. Replace the subset-only arrayContaining
assertion and remove reliance on the separate task_update/task_set_status
exclusions so any newly added tool requires explicit acknowledgment.

In `@tests/unit/interfaces/mcp/mutation-tool-handlers.test.ts`:
- Around line 288-289: Rename the afterEditUpdatedAt variable in the
mutation-tool handler test to reflect that its value is read after both the edit
and the triage no-op, and update the corresponding expectation reference.
- Around line 40-46: Replace the local connect helper in the mutation handler
tests with the hardened connectMcp helper from create-mcp-server.test.ts,
extracting it into a shared test utility if needed. Preserve failed-connect
cleanup, idempotent close behavior, and allSettled-based shutdown, and update
callers to use the shared helper.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 36f8e85c-fbad-4375-bffe-e7cd714a4362

📥 Commits

Reviewing files that changed from the base of the PR and between ba574fe and 6f9a583.

📒 Files selected for processing (26)
  • .gitignore
  • docs/mcp-tools.md
  • docs/superpowers/plans/2026-07-27-issue-21-mcp-mutations-review-fixes.md
  • docs/superpowers/plans/2026-07-27-issue-21-mcp-mutations.md
  • eslint.config.js
  • src/application/tasks/task-application.ts
  • src/application/tasks/use-cases/edit-task.ts
  • src/application/tasks/use-cases/transition-task.ts
  • src/interfaces/contracts/task-contract.ts
  • src/interfaces/http/task-routes.ts
  • src/interfaces/mcp/create-mcp-server.ts
  • src/interfaces/mcp/mapping/change-metadata.ts
  • src/interfaces/mcp/mapping/mcp-errors.ts
  • src/interfaces/mcp/schemas/mcp-output-schema.ts
  • src/interfaces/mcp/schemas/mutation-tool-schemas.ts
  • src/interfaces/mcp/schemas/read-tool-schemas.ts
  • src/interfaces/mcp/tools/register-mutation-tools.ts
  • src/interfaces/mcp/tools/task-archive.ts
  • src/interfaces/mcp/tools/task-complete.ts
  • src/interfaces/mcp/tools/task-edit.ts
  • src/interfaces/mcp/tools/task-start.ts
  • src/interfaces/mcp/tools/task-triage.ts
  • tests/integration/mcp-stdio.test.ts
  • tests/unit/application/tasks/task-application.test.ts
  • tests/unit/interfaces/mcp/create-mcp-server.test.ts
  • tests/unit/interfaces/mcp/mutation-tool-handlers.test.ts

@krishna916
krishna916 merged commit d39af71 into main Jul 27, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement user-directed lifecycle capabilities through MCP

1 participant