Skip to content

Implement MCP capture and read tools - #29

Merged
krishna916 merged 7 commits into
mainfrom
feature/issue-26-implementation
Jul 26, 2026
Merged

Implement MCP capture and read tools#29
krishna916 merged 7 commits into
mainfrom
feature/issue-26-implementation

Conversation

@krishna916

@krishna916 krishna916 commented Jul 26, 2026

Copy link
Copy Markdown
Owner

Summary

  • add five versioned MCP capture/read tools backed by TaskApplication
  • advertise strict per-tool Zod input schemas and use SDK-native InvalidParams for schema-invalid calls
  • return versioned structured success/error envelopes, forced AGENT provenance, advisory duplicate warnings, session reads, and workspace-aware listing
  • add idempotent stdio runtime lifecycle cleanup with ordered server/runtime shutdown

Issue #26 acceptance coverage

  • strict discovery and full invalid-input boundary matrices for all five tools, proving no application invocation
  • focused capture/read success behavior, output-schema parsing, compatibility text parity, and stable error/redaction envelopes for every handler
  • workspace normalization, SQL filtering-before-limit, and prepared-statement cache separation
  • built stdio discovery, session isolation/order, duplicate advisory behavior, post-validation protocol continuity, cleanup, and fatal-startup stderr/stdout/exit-code behavior

Validation

  • pnpm verify
  • focused MCP lifecycle, contract, logger, stdio, application, and SQLite repository suites

No known unverified issue #26 acceptance criteria remain.

Summary by CodeRabbit

  • New Features

    • Added five safe local MCP task tools for capturing, listing, retrieving, finding similar tasks, and viewing session captures.
    • Added structured, versioned responses, standardized errors, validation, duplicate-task warnings, and agent provenance.
    • Added workspace filtering for task lists, including input normalization and bounded limits.
  • Documentation

    • Updated setup instructions, tool contracts, supported endpoints, and implementation planning documentation.
  • Bug Fixes

    • Corrected workspace filtering so results are filtered before limits are applied.

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@krishna916, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 36 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 838f098b-7338-407b-a9a3-9f8396371659

📥 Commits

Reviewing files that changed from the base of the PR and between a101bed and 43f7878.

📒 Files selected for processing (8)
  • README.md
  • docs/mcp-tools.md
  • src/application/tasks/use-cases/list-tasks.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/logger.test.ts
  • tests/unit/interfaces/mcp/mcp-tool-contracts.test.ts
📝 Walkthrough

Walkthrough

Relay now exposes five versioned MCP stdio task tools backed by TaskApplication, adds workspace-aware task listing, standardizes MCP results and errors, and centralizes server lifecycle handling with integration and contract coverage.

Changes

MCP task tools

Layer / File(s) Summary
Workspace-aware task listing
src/application/tasks/..., src/database/tasks/..., tests/integration/task-repository.test.ts, tests/unit/application/tasks/...
Task listing accepts normalized workspace filters, validates them, applies SQL filtering before limits, and separates cached filtered and unfiltered statements.
MCP schemas and result mapping
src/interfaces/contracts/task-contract.ts, src/interfaces/mcp/schemas/..., src/interfaces/mcp/mapping/...
MCP inputs and versioned outputs are defined, duplicate statuses are rejected, task DTOs and match reasons are mapped, and domain errors become stable MCP error envelopes.
Task tool registration
src/interfaces/mcp/create-mcp-server.ts, src/interfaces/mcp/tools/..., tests/unit/interfaces/mcp/create-mcp-server.test.ts, tests/unit/interfaces/mcp/mcp-tool-contracts.test.ts
The server registers task_capture, task_list, task_get, task_find_similar, and session_captures_list, including validation, duplicate warnings, provenance, and structured responses.
Stdio runtime and documentation
src/interfaces/mcp/main.ts, src/interfaces/mcp/run-mcp-server.ts, tests/integration/mcp-stdio.test.ts, tests/unit/interfaces/mcp/run-mcp-server.test.ts, README.md, docs/mcp-tools.md, docs/superpowers/plans/...
Startup, signal shutdown, fatal errors, stdout/stderr behavior, end-to-end stdio operation, and the MCP contract are documented and tested.

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

Possibly related issues

  • krishna916/relay issue 2 — Covers the MCP task-tool capabilities implemented here.
  • krishna916/relay issue 26 — Directly specifies the five MCP tools, schemas, lifecycle wiring, tests, and documentation.
  • krishna916/relay issue 18 — Defines the MCP stdio foundation used by this implementation.
  • krishna916/relay issue 21 — Covers shared schemas, mappings, runtime injection, and registration conventions extended here.

Possibly related PRs

  • krishna916/relay#3 — Refactors the MCP server factory and startup flow extended by this PR.
  • krishna916/relay#12 — Introduces the SQLite task-listing foundation extended with workspace filtering.
  • krishna916/relay#27 — Adds the versioned contract layer and status validation used by these MCP tools.

Sequence Diagram(s)

sequenceDiagram
  participant MCPClient
  participant McpServer
  participant TaskApplication
  MCPClient->>McpServer: task_capture
  McpServer->>TaskApplication: findSimilar(title, workspace, limit)
  TaskApplication-->>McpServer: similar candidates
  McpServer->>TaskApplication: create(task with AGENT provenance)
  TaskApplication-->>McpServer: created task
  McpServer-->>MCPClient: structured result with CREATED and warnings
Loading
🚥 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 matches the main change: adding MCP capture and read 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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/issue-26-implementation

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.

Copy link
Copy Markdown
Owner Author

Review verdict: Changes required before merge

The implementation direction is good: the PR keeps MCP as an adapter over TaskApplication, preserves relay_health, uses structured results, forces AGENT provenance during capture, performs advisory duplicate lookup before creation, and composes the shared runtime in main.ts.

However, the PR does not yet satisfy issue #26. The main blockers are:

  1. MCP tools advertise an unrestricted input schema instead of the approved strict contract schemas.
  2. Most of the required safety, error-mapping, lifecycle, duplicate, and session tests are missing.
  3. The workspace-filter correction changes application and repository contracts without adding the promised application/repository tests.

Please implement the following steps in order. Do not expand scope beyond these corrections.


Step 1 — Register the real MCP input schemas

Problem

All five tools currently register this schema:

const rawToolInputSchema = z.object({}).passthrough();

The handlers later call the strict contract schemas manually, so runtime validation rejects bad input, but MCP discovery tells clients that every object is accepted.

This creates two different contracts:

Agents and MCP clients rely on the advertised schema for tool discovery and argument generation. The advertised schema must therefore be authoritative and match runtime validation.

Required changes

In src/interfaces/mcp/schemas/read-tool-schemas.ts:

  1. Remove rawMcpToolInputSchema unless there is a documented SDK limitation that requires it.
  2. Export the existing strict schemas directly:
    • agentCaptureInputSchema
    • taskListInputSchema
    • taskGetInputSchema
    • findSimilarInputSchema
    • sessionCapturesInputSchema
  3. Preserve the existing output schemas.

In src/interfaces/mcp/tools/register-read-tools.ts:

  1. Register each tool with its own real input schema:
inputSchema: taskListInputSchema
inputSchema: taskGetInputSchema
inputSchema: findSimilarInputSchema
inputSchema: sessionCapturesInputSchema

In src/interfaces/mcp/tools/task-capture.ts:

  1. Register capture with:
inputSchema: agentCaptureInputSchema
  1. Keep explicit parsing inside handlers only if needed for type narrowing or defense in depth. Do not maintain a separate looser public schema.

Tests

Add a tool-discovery assertion that inspects the listed schemas and proves at minimum:

  • task_capture exposes only the approved fields
  • createdByName and sessionId are required
  • caller-controlled status and creator type are absent
  • task_list.limit exposes the approved bounds
  • task_find_similar.limit exposes the approved maximum
  • schemas do not advertise additionalProperties: true

Do not merely test that invalid input is rejected after invocation. Test that discovery exposes the correct contract.


Step 2 — Add focused test helpers before adding cases

The current MCP test file repeats server/client setup. The missing matrix will make it unwieldy.

In tests/unit/interfaces/mcp/create-mcp-server.test.ts, add small local helpers such as:

async function createConnectedMcpTestServer(taskApplication: TaskApplication) {
  // create server, linked transports and client
  // connect both
  // return { server, client, close }
}

Also add a controllable fake or spy TaskApplication factory that can:

  • return configured values
  • throw configured errors
  • record method calls and call order

Do not mock SQLite in MCP unit tests. MCP tests must use an injected application fake or the existing in-memory application fixture.

Ensure every test closes the client/server transports in finally or afterEach so the suite does not leak handles.


Step 3 — Prove task_capture behaviour completely

Add separate tests for each contract rule. Avoid one oversized happy-path test.

3.1 Complete successful capture

Call task_capture with all approved optional fields:

  • title
  • description
  • priority
  • workspace
  • sourceContext
  • createdByName
  • sessionId

Assert that the application receives:

creator: {
  type: 'AGENT',
  name: '<provided createdByName>'
}

Assert that:

  • status is not supplied by the adapter
  • all provenance/session fields are preserved
  • the complete resulting task is returned
  • change.action === 'CREATED'
  • schemaVersion === 1
  • warnings is an array
  • structured content is authoritative
  • compatibility text parses to the same payload

3.2 Duplicate lookup happens before creation

Use a fake application that records calls.

Assert exact order:

findSimilar
create

Do not infer order only from final output.

3.3 Duplicate candidates do not block creation

Configure findSimilar to return one or more tasks.

Assert:

  • create is still called once
  • the new task is returned
  • warning code is POSSIBLE_DUPLICATE
  • warning candidates contain the expected IDs
  • warnings remain advisory and do not produce isError

3.4 No duplicate warning

Configure findSimilar to return no tasks.

Assert warnings is exactly [].

3.5 Reject unsafe caller-controlled fields

Add separate rejected-input tests for at least:

  • status
  • creator
  • createdByType
  • an unrelated unknown key

Each must return:

{
  "schemaVersion": 1,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed."
  }
}

Also assert neither findSimilar nor create is called.

3.6 Boundary validation

Test minimum/maximum and just-outside values for important fields, especially:

  • empty/whitespace title
  • title longer than 300
  • createdByName longer than 100
  • invalid session ID
  • workspace longer than 255
  • sourceContext longer than 1000

Use table-driven tests where practical.


Step 4 — Prove all four read tools individually

Add focused tests instead of relying on the current combined flow.

4.1 task_get

Test:

  • successful result contains { task }
  • exact task ID is passed to the application
  • missing task maps to NOT_FOUND
  • unknown keys are rejected
  • malformed/empty IDs are rejected

4.2 task_list

Test:

  • default statuses are the approved full status set
  • explicit statuses are passed unchanged after schema validation
  • explicit limit is passed
  • default limit is passed
  • workspace string is passed after contract normalization
  • workspace: null is passed as an explicit unassigned-workspace filter
  • omitted workspace remains omitted and does not become null
  • result is { tasks, count }
  • count equals returned task length
  • duplicate/invalid status values are rejected according to the contract
  • limit boundaries are enforced

4.3 task_find_similar

Test:

  • application findSimilar is called with title, workspace and limit
  • no more than five candidates are returned
  • exact title produces EXACT_TITLE
  • normalized-but-not-exact title produces NORMALIZED_TITLE
  • stable match-reason values are returned only from the approved enum
  • invalid limits and unknown keys are rejected

Where possible, avoid recomputing matching rules independently in the adapter. If the application contract already knows the reason, prefer mapping authoritative application data. If issue #20 only returns tasks, retain the current adapter mapping but test exact casing/whitespace behaviour explicitly.

4.4 session_captures_list

Test:

  • session ID is required
  • invalid session IDs are rejected
  • result contains { sessionId, tasks, count }
  • task order matches the application result exactly
  • tasks from another session are not included when using the in-memory repository/application
  • empty session returns an empty list and count 0

Step 5 — Add complete stable error mapping tests

Use injected application fakes. Do not require SQLite to trigger these cases.

Add tests for every required mapping:

Validation

Sources:

  • ZodError
  • InvalidTaskRequestError
  • TaskDomainError

Expected code:

VALIDATION_ERROR

Missing task

Source:

  • TaskNotFoundError

Expected code:

NOT_FOUND

Persistence failure

Source:

  • TaskPersistenceError

Expected code:

STORAGE_ERROR

Unexpected failure

Source:

  • generic Error

Expected code:

INTERNAL_ERROR

For every error case assert:

  • isError === true
  • schemaVersion === 1
  • stable public code
  • stable generic public message
  • compact text matches structured content

Leakage assertions

Throw errors whose messages deliberately include sensitive implementation details, for example:

SQLITE_CONSTRAINT at /Users/example/relay.db
SELECT * FROM tasks
super-secret-token
stack-marker

Assert none of these strings appears anywhere in:

  • structuredContent
  • text content
  • serialized response

The adapter must not expose:

  • SQL
  • stack traces
  • causes
  • database paths
  • secrets
  • internal exception messages

Step 6 — Add application tests for the workspace-list correction

This PR changes the application contract despite issue #26 being adapter-only. The correction is reasonable because MCP task_list must support repository-side workspace filtering before limit, but the change needs direct tests.

In the existing application list-use-case tests, add cases for:

  1. workspace omitted
    • repository query does not contain a workspace property
  2. workspace string
    • leading/trailing whitespace is trimmed
  3. workspace null
    • repository receives explicit null
  4. whitespace-only workspace
  5. invalid limit still fails before repository access

Assert the exact repository query object rather than only returned tasks.

Do not add new business rules beyond the approved contract.


Step 7 — Add SQLite repository integration tests for workspace filtering

Add repository integration tests using a disposable database.

Create tasks across at least these groups:

  • workspace relay
  • workspace other
  • workspace null
  • different statuses

Then test:

7.1 Filter before limit

Insert newer matching and non-matching rows so that an incorrect implementation which limits first and filters in memory would fail.

Example structure:

  • several newest other tasks
  • older relay tasks
  • query workspace relay, status INBOX, limit 2

Expected: two relay tasks, not zero.

7.2 Explicit null workspace

Query with:

workspace: null

Expected: only tasks whose workspace is SQL NULL.

7.3 Omitted workspace

Query without the property.

Expected: tasks from all workspaces.

7.4 Prepared statement cache separation

Call filtered and unfiltered queries with the same status-count shape in alternating order.

Expected: correct results each time. This protects the new ${statusCount}:${filteredByWorkspace} statement-cache key.

7.5 Ordering

Confirm the existing ordering remains:

updated_at DESC, created_at DESC, id ASC

Do not modify schema or migrations for this work.


Step 8 — Make lifecycle composition testable

The current main.ts code is directionally correct but cannot easily prove the issue’s exactly-once cleanup requirements.

Extract the lifecycle orchestration into a focused module or exported function. One acceptable shape is:

export interface McpMainDependencies {
  createRuntime: () => TaskRuntime;
  createServer: (taskApplication: TaskApplication) => McpServerLike;
  createTransport: () => TransportLike;
  onSignal: (...args) => void;
  exit: (code: number) => never | void;
}

export async function runMcpServer(dependencies = productionDependencies): Promise<void> {
  // composition and cleanup only
}

Exact names may vary. Keep production main.ts very small.

Requirements:

  • runtime is created once
  • server is created once
  • transport connects once
  • shutdown is idempotent
  • server close occurs before runtime close
  • runtime closes even if server close throws
  • runtime closes if server creation fails
  • server and runtime close if connect fails
  • repeated SIGINT/SIGTERM does not close either resource twice
  • diagnostics go through the existing stderr logger only
  • no normal diagnostics are written to stdout

Avoid introducing a framework or generic lifecycle abstraction. A small dependency seam is enough.


Step 9 — Add lifecycle unit tests

Using the extracted composition seam, add deterministic tests for:

  1. normal startup and signal shutdown
  2. two rapid shutdown signals
  3. server close throws
  4. runtime creation succeeds but server creation throws
  5. server creation succeeds but connect throws
  6. startup failure reports a non-zero outcome
  7. runtime close is called exactly once in every applicable path
  8. server close is called exactly once in every applicable path
  9. call ordering is server.close then runtime.close

Do not depend solely on real OS signals for unit coverage.


Step 10 — Strengthen built-process stdio integration

Keep the isolated RELAY_DB_PATH and temporary launch directory.

Split the current integration flow into focused tests or a shared process fixture.

Add built-process coverage for:

10.1 Discovery

Assert all six tools are discoverable:

  • relay_health
  • task_capture
  • task_list
  • task_get
  • task_find_similar
  • session_captures_list

10.2 Capture and session retrieval

Capture multiple tasks:

  • two in session A
  • one in session B

Assert:

  • session A returns exactly its two tasks
  • session B returns exactly its one task
  • order matches persisted capture order
  • provenance is AGENT
  • session metadata survives the built process and SQLite round-trip

10.3 Duplicate advisory behaviour

Capture the same or normalized-equivalent title twice.

Assert:

  • second capture succeeds
  • a duplicate warning is returned
  • both tasks persist

10.4 Protocol remains usable after validation failure

Send an invalid request, assert stable VALIDATION_ERROR, then immediately call relay_health or a valid task tool.

Expected: subsequent protocol request succeeds.

10.5 Protocol-clean stdout

The MCP client successfully communicating is useful evidence, but add an explicit assertion where practical that application diagnostics do not appear as stray protocol messages.

If direct stdout capture conflicts with StdioClientTransport, add a separate child-process lifecycle test that captures raw stdout/stderr and verifies startup/shutdown diagnostics appear only on stderr.

10.6 Cleanup

Use try/finally so client, transport, child process, and temporary directory are cleaned even when an assertion fails.

Do not call rmSync only at the end of the happy path.


Step 11 — Verify output contracts directly

For each of the five tools, add at least one assertion that validates the actual returned structuredContent against the corresponding output Zod schema.

Examples:

taskCaptureOutputSchema.parse(result.structuredContent)
taskListOutputSchema.parse(result.structuredContent)

Also parse the JSON compatibility text and assert it equals structuredContent.

This guards against accidental drift between:

  • TypeScript return objects
  • MCP advertised output schema
  • compact compatibility content

Step 12 — Documentation correction

After the implementation and tests are complete:

  1. Update docs/mcp-tools.md only where actual behaviour changed.
  2. Ensure it clearly states that the five tools are implemented.
  3. Document that discovery exposes strict input schemas.
  4. Document stable error codes and generic messages.
  5. Document duplicate warnings as advisory.
  6. Document that capture always uses AGENT creator type.
  7. Keep mutation tools explicitly out of scope.
  8. Keep README instructions limited to starting the built stdio server and the currently implemented tools.

Do not document lifecycle guarantees or fields that are not verified by tests.


Step 13 — Required verification sequence

Run the smallest relevant checks while implementing, then the full gate.

Suggested sequence:

pnpm test -- tests/unit/interfaces/mcp/create-mcp-server.test.ts
pnpm test -- tests/unit/application/tasks
pnpm test -- tests/integration/task-repository.test.ts
pnpm test -- tests/integration/mcp-stdio.test.ts
pnpm typecheck
pnpm lint
pnpm test:coverage
pnpm build
pnpm verify

If actual test paths differ, use the repository’s existing paths but preserve this progression.

Before marking the PR ready:

  • confirm pnpm verify passes without rewriting files
  • confirm CI passes on the latest commit
  • inspect git diff and remove unrelated formatting or scope changes
  • update the PR description with the exact tests added

Completion checklist

Do not request re-review until all items below are true:

  • Every MCP tool advertises its strict approved input schema.
  • Tool discovery tests inspect schemas, not only names.
  • Capture call order is tested.
  • Duplicate warnings are tested and do not block capture.
  • Forced AGENT provenance is tested.
  • Unsafe status/creator injection is tested.
  • Boundary and unknown-key validation is tested.
  • NOT_FOUND, STORAGE_ERROR, and INTERNAL_ERROR mappings are tested.
  • Error responses are proven not to leak SQL, paths, causes, secrets, or stacks.
  • All four read tools have focused success and validation tests.
  • Session isolation and order are tested.
  • Workspace filtering is tested at application and SQLite repository layers.
  • Filtering-before-limit is proven with an integration test.
  • Lifecycle cleanup is testable through injected dependencies.
  • Runtime/server exactly-once cleanup is tested.
  • Built stdio tests use isolated disposable databases.
  • Built-process duplicate and session round-trips are tested.
  • Compatibility text equals authoritative structured content.
  • All tool outputs validate against their declared output schemas.
  • Documentation matches verified behaviour.
  • pnpm verify and CI pass on the final commit.

Keep the current architectural direction. This review does not request persistence redesign, new domain behaviour, mutation tools, CLI work, skills, vendor integrations, authentication, packaging, or other issue #26 out-of-scope work.

Copy link
Copy Markdown
Owner Author

Decision resolved: implement Option 1

The contract conflict has been resolved in favour of strict advertised schemas with SDK-native MCP InvalidParams for malformed inputs.

Issue #26 has been updated with the authoritative behavior and test requirements. Issue #19 also has a contract-clarification comment documenting the distinction between protocol validation errors and Relay tool-execution errors.

Terra implementation instruction

Please update this PR using the normal MCP SDK v1.29.0 registerTool path. Do not implement a lower-level MCP request-handler override.

Follow these steps:

  1. Register each tool with its actual strict contract input schema:

    • task_capture -> agentCaptureInputSchema
    • task_list -> taskListInputSchema
    • task_get -> taskGetInputSchema
    • task_find_similar -> findSimilarInputSchema
    • session_captures_list -> sessionCapturesInputSchema
  2. Remove rawMcpToolInputSchema if it has no remaining valid use.

  3. Treat malformed request shape as an SDK protocol concern:

    • missing required fields
    • unknown keys
    • invalid values/types/limits
    • forbidden status or creator fields
    • malformed session IDs

    These calls must fail with SDK-native MCP InvalidParams; do not convert them to Relay VALIDATION_ERROR tool results.

  4. Keep Relay structured tool errors for schema-valid requests that reach the handler:

    • post-schema domain/application validation -> VALIDATION_ERROR
    • missing task -> NOT_FOUND
    • persistence failure -> STORAGE_ERROR
    • unexpected failure -> INTERNAL_ERROR
  5. Keep structured success results unchanged:

    {
      "schemaVersion": 1,
      "data": {},
      "warnings": []
    }
  6. Add focused discovery tests that assert important schema properties rather than snapshotting the entire generated JSON schema:

    • required fields
    • enum values
    • numeric bounds
    • additionalProperties: false
  7. Add invalid-input tests proving:

    • client.callTool() rejects with MCP InvalidParams
    • the application handler/fake is not invoked
  8. Add injected-fake tests for schema-valid execution failures:

    • NOT_FOUND
    • STORAGE_ERROR
    • INTERNAL_ERROR
    • no SQL, stack trace, cause, secret, or local-path leakage
  9. Complete the remaining issue Implement MCP read and autonomous-capture tools #26 review gaps:

    • prove findSimilar is called before create
    • prove duplicate warnings do not block capture
    • prove forced AGENT provenance and session metadata
    • prove session isolation and persisted ordering
    • test workspace filtering before limit at application/repository level
    • prove runtime cleanup exactly once on signal and startup/connect failure
    • keep MCP stdout protocol-clean
  10. Update docs/mcp-tools.md to explicitly distinguish:

    • schema-invalid call -> MCP InvalidParams
    • schema-valid execution failure -> Relay structured tool error
  11. Run:

    pnpm format:check
    pnpm lint
    pnpm typecheck
    pnpm test
    pnpm test:coverage
    pnpm build
    pnpm verify
  12. In the PR summary, list the tests added for each acceptance criterion and note any criterion that remains unverified.

Scope guard

Do not add custom protocol dispatch, mutation tools, CLI behavior, skills, packaging, authentication, or unrelated refactoring in this PR.

@krishna916
krishna916 marked this pull request as ready for review July 26, 2026 19:04
@krishna916 krishna916 linked an issue Jul 26, 2026 that may be closed by this pull request
10 tasks

@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.

Actionable comments posted: 6

🧹 Nitpick comments (3)
tests/unit/interfaces/mcp/mcp-tool-contracts.test.ts (2)

420-451: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

This matrix is fully subsumed by the per-tool matrix below.

Lines 453-503 run the identical six error/code pairs for task_get (plus the other four tools) with the same envelope and leak assertions. Dropping this block removes ~30 duplicated lines without losing coverage. Extracting the errors array to a module-level constant would also avoid re-declaring it inside the loop.

🤖 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/mcp-tool-contracts.test.ts` around lines 420 - 451,
Remove the duplicated schema-valid execution error matrix beginning with the
task_get test, since the per-tool matrix below already covers the same six
error/code mappings and leak assertions. Preserve the broader per-tool coverage,
and optionally hoist the shared errors array to a module-level constant to avoid
redeclaring it inside the loop.

100-109: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert captured input after the call rather than inside the mock.

The tool handler wraps execution in try/catch (src/interfaces/mcp/tools/task-capture.ts lines 17-46), so an assertion thrown here is swallowed and re-surfaces as an INTERNAL_ERROR envelope. The test still fails, but on a downstream schema-parse assertion with a misleading message. Recording the argument and asserting outside keeps failures readable.

♻️ Proposed refactor
+    let captureInput: unknown;
     const application = taskApplication({
       findSimilar: vi.fn(() => {
         calls.push('findSimilar');
         return [task({ id: 'existing' })];
       }),
       create: vi.fn((input) => {
         calls.push('create');
-        expect(input).toMatchObject({
-          creator: { type: 'AGENT', name: 'Codex' },
-          sessionId: 'session-a',
-          sourceContext: 'issue-26',
-        });
-        expect(input).not.toHaveProperty('status');
+        captureInput = input;
         return task({ sourceContext: 'issue-26' });
       }),
     });

Then assert after callTool:

expect(captureInput).toMatchObject({
  creator: { type: 'AGENT', name: 'Codex' },
  sessionId: 'session-a',
  sourceContext: 'issue-26',
});
expect(captureInput).not.toHaveProperty('status');
🤖 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/mcp-tool-contracts.test.ts` around lines 100 - 109,
Update the create mock in the relevant test to record its input in a capture
variable instead of asserting inside the mock. After callTool completes, assert
the captured input matches the expected creator, sessionId, and sourceContext
and does not contain status, preserving the existing task return behavior.
tests/unit/interfaces/mcp/logger.test.ts (1)

5-11: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Restore the stdio spies and prefer mockClear over mockReset.

Two issues with this setup:

  1. The spies are installed during collection and never restored, so process.stdout.write / process.stderr.write stay stubbed for the rest of the worker's lifetime, potentially swallowing other output.
  2. mockReset() drops the () => true implementation, so any test added after the first would get a spy returning undefined from write.
♻️ Proposed fix
-import { afterEach, describe, expect, it, vi } from 'vitest';
+import { afterAll, afterEach, describe, expect, it, vi } from 'vitest';
 import { mcpLogger } from '../../../../src/interfaces/mcp/logger.js';
 
 describe('mcpLogger', () => {
   const stderr = vi.spyOn(process.stderr, 'write').mockImplementation(() => true);
   const stdout = vi.spyOn(process.stdout, 'write').mockImplementation(() => true);
 
   afterEach(() => {
-    stderr.mockReset();
-    stdout.mockReset();
+    stderr.mockClear();
+    stdout.mockClear();
+  });
+
+  afterAll(() => {
+    stderr.mockRestore();
+    stdout.mockRestore();
   });
🤖 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/logger.test.ts` around lines 5 - 11, Update the
stdio spy cleanup around stderr and stdout to call mockClear() after each test,
preserving their mock implementations, and restore both spies so
process.stdout.write and process.stderr.write are returned to their originals
rather than remaining stubbed for the worker lifetime.
🤖 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.

Inline comments:
In `@docs/mcp-tools.md`:
- Line 3: Update the Issue `#26` tool contract documentation to remove CONFLICT
and ARCHIVED_TASK from the documented execution error-code list. Keep
VALIDATION_ERROR, NOT_FOUND, STORAGE_ERROR, and INTERNAL_ERROR unchanged, and
preserve the surrounding input-schema and structured-response requirements.

In `@README.md`:
- Around line 40-47: Update the README’s outdated MCP statements: remove or
revise the claim that production MCP task handlers are downstream work, change
the mcp/ directory description to reflect shipped task behavior, and revise the
MVP scope statement to acknowledge production MCP task tools. Clarify the
tool-count wording near the MCP tool list so it identifies five task tools plus
the separate relay_health tool.

In `@src/application/tasks/use-cases/list-tasks.ts`:
- Around line 22-24: Update the workspace handling in the task list use case to
validate the input before calling trim(). Reject any non-string, non-null
workspace value with InvalidTaskRequestError, while preserving undefined, null,
and trimmed string normalization and the existing repository.list flow.

In `@tests/integration/mcp-stdio.test.ts`:
- Around line 11-13: Update the MCP integration setup around beforeAll so the
pnpm build:node operation has sufficient time to complete during Vitest setup.
Either configure a larger test.setupTimeout in vitest.config.ts or provide an
explicit timeout to this beforeAll callback, preserving the existing build
command and setup behavior.
- Around line 86-90: The session capture test should not assert task IDs in
UUID-derived order. Update the assertions around sessionA.structuredContent to
verify the expected count and that both first and second task IDs are present,
without requiring a specific ordering; alternatively, configure a deterministic
monotonic ID generator for this test.

In `@tests/unit/interfaces/mcp/create-mcp-server.test.ts`:
- Around line 36-54: Ensure every MCP test that connects a Client and server
closes both in all outcomes. Update the tests around createMcpServer,
client.connect, and server.connect (including the additional referenced cases)
to use try/finally or a shared idempotent close helper, invoking client.close()
and server.close() even when assertions or setup fail.

---

Nitpick comments:
In `@tests/unit/interfaces/mcp/logger.test.ts`:
- Around line 5-11: Update the stdio spy cleanup around stderr and stdout to
call mockClear() after each test, preserving their mock implementations, and
restore both spies so process.stdout.write and process.stderr.write are returned
to their originals rather than remaining stubbed for the worker lifetime.

In `@tests/unit/interfaces/mcp/mcp-tool-contracts.test.ts`:
- Around line 420-451: Remove the duplicated schema-valid execution error matrix
beginning with the task_get test, since the per-tool matrix below already covers
the same six error/code mappings and leak assertions. Preserve the broader
per-tool coverage, and optionally hoist the shared errors array to a
module-level constant to avoid redeclaring it inside the loop.
- Around line 100-109: Update the create mock in the relevant test to record its
input in a capture variable instead of asserting inside the mock. After callTool
completes, assert the captured input matches the expected creator, sessionId,
and sourceContext and does not contain status, preserving the existing task
return behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3937ae9d-48b8-43dd-b94b-3b1a472b818a

📥 Commits

Reviewing files that changed from the base of the PR and between 2183993 and a101bed.

📒 Files selected for processing (24)
  • README.md
  • docs/mcp-tools.md
  • docs/superpowers/plans/2026-07-26-issue-26-mcp-tools.md
  • src/application/tasks/task-repository.ts
  • src/application/tasks/use-cases/list-tasks.ts
  • src/database/tasks/sqlite-task-repository.ts
  • src/interfaces/contracts/task-contract.ts
  • src/interfaces/mcp/create-mcp-server.ts
  • src/interfaces/mcp/main.ts
  • src/interfaces/mcp/mapping/mcp-errors.ts
  • src/interfaces/mcp/mapping/mcp-result.ts
  • src/interfaces/mcp/mapping/task-mcp-dto.ts
  • src/interfaces/mcp/run-mcp-server.ts
  • src/interfaces/mcp/schemas/read-tool-schemas.ts
  • src/interfaces/mcp/tools/register-read-tools.ts
  • src/interfaces/mcp/tools/task-capture.ts
  • tests/integration/mcp-stdio.test.ts
  • tests/integration/task-repository.test.ts
  • tests/unit/application/tasks/task-application.test.ts
  • tests/unit/application/tasks/task-test-fixtures.ts
  • tests/unit/interfaces/mcp/create-mcp-server.test.ts
  • tests/unit/interfaces/mcp/logger.test.ts
  • tests/unit/interfaces/mcp/mcp-tool-contracts.test.ts
  • tests/unit/interfaces/mcp/run-mcp-server.test.ts

Comment thread docs/mcp-tools.md Outdated
Comment thread README.md
Comment thread src/application/tasks/use-cases/list-tasks.ts
Comment thread tests/integration/mcp-stdio.test.ts Outdated
Comment thread tests/integration/mcp-stdio.test.ts Outdated
Comment thread tests/unit/interfaces/mcp/create-mcp-server.test.ts
@krishna916
krishna916 merged commit ba574fe into main Jul 26, 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 MCP read and autonomous-capture tools

1 participant