Resolves 0 conflicts (auto-merge; the branches touched disjoint regions
of src/mcp/mcp-core.js). Fixes audit P0-4 (DC-166 drift: the fix branch
was never merged, so the branch shipped 17 tools while changelog/
capabilities claimed the expanded set, and the workflows UI was broken)
and the production Workflows outage.
Incoming:
- src/mcp/mcp-core.js: 11 new tool handlers over existing routes
(calendar events/add_source, security events/summary, license_status,
capabilities, DNS add/remove record, deploy_recipe, run_workflow,
tailscale_status); DC-162 machine-only gate preserved
- routes/workflows.js: double-prefix fix — declarations are mount-
relative (/history before /:workflowId/history); the dashboard's
single-prefix calls no longer 404 (Premium feature was dead in prod)
- __tests__/mcp/mcp-core-dc166{,-integration}.test.js: tool/schema +
route-existence verifier (scoped to the 11 new tools; extension to
all 28 is the MCP truth batch, audit #40)
Merge-commit fixes (judge r1 C -> r2 A, urn:ump:2jdpii43.../5clu4udr...):
1. integration-test header over-claimed COMPLETE tool coverage — scope
narrowed to the DC-166 additions, stated explicitly
2. routes/workflows.js: shadowed top-level ok import removed (all uses
inside the factory use deps.ok) + comment documenting the trap
Verified on merged tree: TOOLS.length=28, MCP+workflows 44/44.
Judge A — urn:ump:5clu4udrbwuwxn74tqwxtukfjnrwkrbiykp6uh66ipipzxr32xsq
Owner directive "Do it" (2026-10-09): expand the MCP tool set so the
"manage your entire infrastructure" claim is true of the product. 11 new
tools over EXISTING routes: calendar (events/add_source), security
(events/summary), license_status, capabilities, DNS add/remove record,
deploy_recipe, run_workflow, tailscale_status. Handlers verified against
the actual route declarations; credential TYPE passthrough and the DC-162
machine-only tools/call gate unchanged (tests included).
judge r1 (grade C, urn:ump:fyvivcvrphjm5wk227ujr2yzfcgcdvwekjmw6lvnqvjosqrjhtbq)
blocking issues — all fixed in this revision:
1. WORKFLOWS DOUBLE-PREFIX (real product bug the judge caught):
routes/workflows.js declared literal '/workflows/...' paths while
src/app.js mounts the router at /workflows — composed path was
/api/v1/workflows/workflows/..., which the SHIPPED dashboard bundle
(status/js/bundled-workflows.js calls single-prefix /api/v1/workflows/)
never hits: the workflows UI has been broken in production. Fixed by
making route paths RELATIVE to the mount (same class as the recipes
fix); run-workflow MCP path now matches. Also reordered /history
before /:workflowId/history so the literal segment is not captured as
an id (limit 100 vs 50 asserted in tests).
2. Verifier substring check replaced: NEW integration suite
(__tests__/mcp/mcp-core-dc166-integration.test.js) resolves EVERY MCP
tool call's complete mounted (method, path) against the declared route
patterns extracted from the owning route file (params matched as
patterns, comments excluded) — a double prefix or wrong method fails
the run. Plus real-composition dispatch through the actual workflows
router: POST /api/v1/workflows/:id/run reaches the run handler
(sentinel '"ran":true'), list/history handlers land correctly, and a
static guard fails any route file that re-declares its own mount name.
3. Both verbatim-command claims in the brief now name their file.
polish applied: calendar window-math test bounds tightened to exactly
~7 days (was a weak 6-hour lower bound); extra blank line before
tools/list removed; calendar_add_source schema gained the token property
the route already accepts (schema now matches the documented API).
Tests: 73 prior + 15 dc166 unit + 6 integration = 94 MCP tests green;
full suite 6 failed + 3697 passed == 3703 total (known-red billing
family, band-guarded; base-proof shows the same 6 red at a1b8fa3).
eslint: 0 errors on touched files (warnings count unchanged vs base).
Routes covered in this batch:
- routes/events.js (1 call: GET /status)
- routes/workflows.js (6 calls: GET/POST/PUT/DELETE /workflows, POST /test, POST /:id/toggle)
- routes/openclaw.js (4 calls: GET /:hostname, DELETE /:hostname, POST /connect, GET /status)
- routes/dns.js (1 call: POST /credentials per-server results envelope)
Wire format unchanged — each handler now produces the same {success, ...} shape via success(). Net result: every {success, ...} envelope in routes/ now flows through the response helper, leaving only the intentional raw-array calls (services.js) and error-path envelopes for separate cleanup.
Convert ~160 raw res.json()/res.status().json() calls across 32+ files
to use centralized helpers from src/utils/responses.js (ok, errorResponse,
successMessage, notFound, validationError, forbidden, unauthorized, conflict).
No behavior changes — response shapes are identical. Future schema changes
(e.g., requestId envelope) only need to update one module.
Fix error vs errorResponse signature mismatch in routes/health.js CA cert
endpoint where error(res, message, statusCode) was being called with
errorResponse(res, statusCode, message, extras) argument order.
Files changed: middleware.js, csrf-protection.js, error-handler.js,
license-manager.js, src/app.js, and 27 route files.
Test suite: 755 pass / 4 pre-existing failures (services credential tests).