LangENKO

MCP tools (Phase 14.3)

Four new tools added to `@mandujs/mcp` in Phase 14.3 — `mandu.run.tests`, `mandu.deploy.preview`, `mandu.ai.brief`, and `mandu.loop.close`. Each closes the loop between an agent's actions and its orchestrator.

since v0.25
On this page

MCP tools (Phase 14.3)

Four new tools added to @mandujs/mcp as part of Phase 14.3. They close the loop between an agent's actions and the orchestrator that drives it: run the project's tests, preview a deploy without touching production, build a structured briefing for a fresh agent, and convert raw output into an actionable next-step prompt.

All four follow the existing packages/mcp/src/tools/* convention: an exported *ToolDefinitions: Tool[] array plus an exported *Tools(projectRoot) handler factory, registered via TOOL_MODULES in packages/mcp/src/tools/index.ts.

1. mandu.run.tests

Runs mandu test as a child process, parses the bun-test output, returns a structured summary.

Input schema

Field Type Default Description
target "unit" | "integration" | "e2e" | "all" "all" Subcommand passed through to mandu test.
filter string? Forwarded as --filter <pattern> to bun test.
coverage boolean? false Adds --coverage.

Output shape

{
  target: "unit" | "integration" | "e2e" | "all",
  passed: number,
  failed: number,
  skipped: number,
  duration_ms?: number,
  failing_tests: Array<{ name: string; file?: string; error?: string }>,
  exit_code: number,
  note?: "no test files" | "timed out",
  stdout_tail?: string,   // last 2000 chars, for diagnostics
  stderr_tail?: string,
}

On validation failure the tool returns { error, field, hint } with isError: true propagated by the MCP error handler. A child-process timeout is enforced at 10 minutes.

Empty test dirs produce { passed: 0, failed: 0, skipped: 0, note: "no test files" } — callers get a benign zeroed summary instead of a crash.

2. mandu.deploy.preview

Invokes mandu deploy --target=<target> --dry-run. Always dry-run; the tool cannot trigger a real deployment.

Input schema

Field Type Required Description
target one of docker | fly | vercel | railway | netlify | cf-pages | docker-compose yes Deployment adapter target.

Output shape

{
  target: DeployTarget,
  mode: "dry-run",
  artifact_list: Array<{
    path: string;
    preserved: boolean;
    description?: string;
  }>,
  warnings: string[],
  diff?: string,          // parsed from fenced diff blocks if present
  exit_code: number,
  stdout_tail?: string,
  stderr_tail?: string,
}

The artifact marker + (new) vs (preserved) maps to preserved: false | true. Warning lines starting with ⚠️ or Warning: are collected separately into warnings.

3. mandu.ai.brief

Assembles a structured briefing for an AI agent newly attaching to the project. Use it as the first tool an onboarded agent calls.

Input schema

Field Type Default Description
depth "short" | "full" "short" short trims lists for fast ingestion; full returns the complete view.

Output shape

{
  title: string,                 // "<pkg.name> @ <version>"
  summary: string,               // pkg.description or default
  depth: "short" | "full",
  files: string[],               // package.json, mandu.config.*, AGENTS.md, CLAUDE.md, manifest
  skills: Array<{ id; source: "static" | "generated"; path? }>,
  recent_changes: Array<{ hash; subject; author?; date? }>,   // last 20 commits
  docs: Array<{ path; title }>,  // top-level docs/*.md files
  config: {
    guard_preset?: string,
    fs_routes?: boolean,
    has_playwright?: boolean,
  },
  suggested_next: string[],      // derived heuristics
}

The tool is read-only. It invokes git log as a 10-second-capped child process; failures produce empty recent_changes rather than erroring.

4. mandu.loop.close

Adapts the pure closeLoop() function from @mandujs/skills/loop-closure into an MCP tool surface. Given stdout, stderr, and exitCode from the most recent child-process run, it identifies the dominant stall pattern and composes an advisory nextPrompt.

Input schema

Field Type Default Description
stdout string? "" Captured stdout.
stderr string? "" Captured stderr.
exitCode number? 0 Child-process exit code.
detectors string[]? all Optional allow-list of detector IDs.

Output shape

{
  stallReason: string,
  nextPrompt: string,
  evidence: Array<{ kind; file?; line?; snippet; label? }>,
  detectors_run: string[],
}

Safety

mandu.loop.close is pure: the underlying function never writes files, never spawns processes, and never performs I/O. It is declared readOnlyHint: true. The returned nextPrompt is advisory text — an orchestrator decides whether to feed it back into the agent.

See Loop Closure for the full list of detectors and sample prompts.

Tool registration

All four are registered through the standard TOOL_MODULES array in packages/mcp/src/tools/index.ts. They appear in the mandu-mcp server's list_tools response without any profile enabled (i.e. in the default full profile).

To expose them in the minimal or standard profiles, add the category IDs (run-tests, deploy-preview, ai-brief, loop-close) to packages/mcp/src/profiles.ts.

Testing

Test files mirror the tools under packages/mcp/tests/tools/:

  • run-tests.test.ts — 14 tests (definition shape, input validation, parser correctness)
  • deploy-preview.test.ts — 14 tests (definition shape, input validation, artifact/warning/diff parsing)
  • ai-brief.test.ts — 14 tests (definition shape, fake-project handler, buildSuggestedNext heuristics)
  • loop-close.test.ts — 13 tests (definition shape, validation, determinism, detector allow-list)

Run with:

cd packages/mcp && bun test

Example end-to-end flow

The intended composition of these four tools:

Agent runs a task
    ↓
mandu.run.tests  →  exit_code = 1, failing_tests populated
    ↓
mandu.loop.close(stdout, stderr, exit_code=1)
    ↓
  stallReason: "3 test failures detected"
  nextPrompt:  "# Stall detected..."
    ↓
Orchestrator feeds nextPrompt back to agent
    ↓
Agent proposes changes, runs mandu.deploy.preview(target=fly)
    ↓
  mode: "dry-run"
  artifact_list: [ { path: "fly.toml", preserved: true }, ... ]
    ↓
Agent ready for human-approved deploy

Each tool is independently useful; together they cover the stall → recover → ship path.

🤖 Agent Prompt

🤖 Agent Prompt — MCP tools (Phase 14.3)
Apply the guidance from the Mandu docs page at https://mandujs.com/docs/ai/mcp-tools to my project.

Summary of the page:
Phase 14.3 Agent G adds 4 MCP tools: run.tests (runs mandu test, returns structured summary), deploy.preview (mandu deploy --dry-run adapter), ai.brief (project briefing for new agents), loop.close (pure stall-pattern detector → nextPrompt). All four in TOOL_MODULES in packages/mcp/src/tools/index.ts.

Required invariants — must hold after your changes:
- All four tools ship in the default `full` MCP profile — appear in `list_tools`
- `mandu.loop.close` is pure (readOnlyHint: true) — no I/O, no spawn
- `mandu.deploy.preview` always passes `--dry-run` — cannot trigger real deployments
- `mandu.run.tests` child process timeout: 10 minutes
- `mandu.ai.brief` is read-only — git log is cap'd at 10s, failure → empty recent_changes

Then:
1. Make the change in my codebase consistent with the page.
2. Run `bun run guard` and `bun run check` to verify nothing
   in src/ or app/ breaks Mandu's invariants.
3. Show me the diff and any guard violations.

For Agents

{
  "schema": "mandu.mcp.tools/v0.25",
  "phase": "14.3",
  "new_tools": [
    { "id": "mandu.run.tests", "category": "run-tests", "writes": false, "spawns": true, "timeout_ms": 600000 },
    { "id": "mandu.deploy.preview", "category": "deploy-preview", "writes": false, "spawns": true, "mode": "always --dry-run" },
    { "id": "mandu.ai.brief", "category": "ai-brief", "writes": false, "spawns": true, "readOnlyHint": true },
    { "id": "mandu.loop.close", "category": "loop-close", "writes": false, "spawns": false, "readOnlyHint": true, "pure": true }
  ],
  "profile_default": "full (all four visible)",
  "rules": [
    "loop.close is pure — no side effects, safe to call speculatively",
    "deploy.preview cannot trigger real deploys — always --dry-run",
    "run.tests child process capped at 10 minutes",
    "ai.brief is read-only — treat as a safe warm-up call"
  ]
}

For Agents

AI hint

Phase 14.3 Agent G adds 4 MCP tools: run.tests (runs mandu test, returns structured summary), deploy.preview (mandu deploy --dry-run adapter), ai.brief (project briefing for new agents), loop.close (pure stall-pattern detector → nextPrompt). All four in TOOL_MODULES in packages/mcp/src/tools/index.ts.

Invariants
  • All four tools ship in the default `full` MCP profile — appear in `list_tools`
  • `mandu.loop.close` is pure (readOnlyHint: true) — no I/O, no spawn
  • `mandu.deploy.preview` always passes `--dry-run` — cannot trigger real deployments
  • `mandu.run.tests` child process timeout: 10 minutes
  • `mandu.ai.brief` is read-only — git log is cap'd at 10s, failure → empty recent_changes
Guard scope
mcp