Skip to content

feat(DIARCHERS-1521): add MCP write endpoints + fix log/artifacts/trigger#627

Closed
Jiachen0715 wants to merge 1 commit into
masterfrom
feat/DIARCHERS-1521-mcp-backend-fixes-and-write-ops
Closed

feat(DIARCHERS-1521): add MCP write endpoints + fix log/artifacts/trigger#627
Jiachen0715 wants to merge 1 commit into
masterfrom
feat/DIARCHERS-1521-mcp-backend-fixes-and-write-ops

Conversation

@Jiachen0715

Copy link
Copy Markdown
Collaborator

Summary

Fixes three defects in the MCP backend surfaced during test-env
integration (build_3201) and adds the 5 MCP write endpoints the
feat/mcp-restart-rerun branch name promised.

Branch base: feat/mcp-restart-rerun. This PR therefore carries
the 8 upstream commits from #617-#625 in addition to the single
commit authored here. Once #620 (traffic isolation) and #621
(restart/rerun endpoints) land on master, the base can be switched
or this PR can be rebased.

DIARCHERS-1521 — Backend fixes

  1. get_job_log silent empty response: the MCP endpoint queried
    only the console streaming table. The scheduler archives job
    logs to job.console on termination and DELETEs the streaming
    rows, so every finished job returned HTTP 200 with an empty body.
    Fixed with a two-stage lookup: job.console archive column
    first, fall back to console for jobs still running.

  2. list_job_artifacts returns 500 unconditionally: the MCP
    endpoint queried a non-existent archive table. archive is a
    jsonb[] column on the job table (migration 00009.sql).
    Rewrote to SELECT archive FROM job and unpack the array,
    matching the legacy endpoint behavior.

  3. POST /trigger creates zombie builds: the MCP endpoint only
    inserted a build row without the seed create_job_matrix job
    the scheduler polls for, so every trigger returned HTTP 200 +
    build_id but the build never ran. Also hardcoded
    restart_counter=0, diverging from schema default 1 and hiding
    the build from legacy UI filters. Fixed by resolving
    source_upload_id per project type (upload projects reuse the
    most recent source_upload; test projects allow NULL), inserting
    the Create Jobs seed in the same transaction, moving the success
    audit entry to after the seed job commits, and removing the
    restart_counter=0 override.

5 new MCP write endpoints

All require allow_trigger=true on the MCP token, share the
trigger_build rate-limit bucket (5 RPM), and are fully audited.

Method Path Handler Semantics
POST /builds/<bid>/restart MCPBuildRestart New build, cloned Create Jobs seed
DELETE /builds/<bid>/abort MCPBuildAbort Insert abort rows for all jobs in build
POST /jobs/<jid>/restart MCPJobRestart Restart job + DAG downstream
POST /jobs/<jid>/rerun MCPJobRerun Rerun single job only
DELETE /jobs/<jid>/abort MCPJobAbort Insert abort row for single job

Handlers do not delegate to the legacy /api/v1/*
implementations, which hard-depend on
g.token['type'] in ('user', 'project'). MCP handlers use
get_mcp_user_id() and reimplement the SQL directly. Shared helper
_restart_or_rerun_job() covers both restart_job (DAG-propagating)
and rerun_job (single-job) paths.

Dashboard UI

src/dashboard-client/src/components/user/UserGlobalTokens.vue:
moved the MCP Tokens section to the top of the page, ahead of Global
Viewer Tokens and Project Tokens. Rationale: MCP Tokens is the
newest feature and the highest-traffic section for users onboarding
to the MCP integration.

…eorder UserGlobalTokens

Three defects in the MCP backend surfaced during test-env integration
(build_3201), and the 5 MCP write endpoints promised by the
feat/mcp-restart-rerun branch name had never been implemented. Also
reordered the token UI to put MCP Tokens first. Bug identifiers
follow the internal tracker; Bug C is handled separately.

Bug E (get_job_log silent empty response):
- MCP endpoint only queried the `console` streaming table
- Scheduler archives logs to `job.console` on termination and DELETEs
  the streaming rows, so every finished job returned HTTP 200 with
  empty body
- Fixed with a two-stage lookup: `job.console` archive column first,
  fall back to `console` streaming table for jobs still running

Bug F (list_job_artifacts returns 500 unconditionally):
- MCP endpoint queried a non-existent `archive` table
- `archive` is actually a jsonb[] column on the `job` table
  (see migration 00009.sql)
- Rewrote the query to `SELECT archive FROM job` and unpack the
  array, matching the legacy endpoint behavior

Bug G (POST /trigger creates zombie builds):
- MCP endpoint only inserted a build row without the seed
  create_job_matrix job that the scheduler polls for
- Every trigger returned HTTP 200 + build_id but left a build that
  never ran, punching holes in the build_number sequence
- Also hardcoded restart_counter=0, diverging from the schema
  default of 1 and making the build invisible to legacy UI filters
- Fixed by adding source_upload_id resolution (upload projects
  reuse the most recent source_upload; test projects allow NULL),
  inserting the Create Jobs seed in the same transaction, moving
  the success audit entry to after the seed job commits, and
  removing the restart_counter=0 override

5 new MCP write endpoints, all requiring allow_trigger on the token,
sharing the trigger_build rate-limit bucket, and fully audited:
- POST   /api/v1/mcp/projects/<id>/builds/<bid>/restart
- DELETE /api/v1/mcp/projects/<id>/builds/<bid>/abort
- POST   /api/v1/mcp/projects/<id>/jobs/<jid>/restart   (cascades downstream)
- POST   /api/v1/mcp/projects/<id>/jobs/<jid>/rerun     (does NOT cascade)
- DELETE /api/v1/mcp/projects/<id>/jobs/<jid>/abort

Handlers do not delegate to legacy /api/v1/* implementations which
hard-depend on g.token['type'] in ('user', 'project'); MCP handlers
use get_mcp_user_id() and reimplement the SQL directly. Shared
helper _restart_or_rerun_job() covers both the DAG-propagating
restart_job and the single-job rerun_job paths.

Dashboard UI:
- src/dashboard-client/src/components/user/UserGlobalTokens.vue:
  moved MCP Tokens section to the top of the page, ahead of Global
  Viewer Tokens and Project Tokens. Rationale: MCP Tokens is the
  newest feature and the highest-traffic section for users
  onboarding to the MCP integration.

Verified:
- Python syntax check passes on builds.py and jobs.py
- All 5 new handlers registered by Flask-RESTX (verified via ast walk)
- Existing MCP endpoints unaffected (legacy /api/v1/projects/*
  handlers left untouched)

Follows: DIARCHERS-1498
Corresponding client PR: sparta-infra/InfraBox-mcp#6
@Jiachen0715

Copy link
Copy Markdown
Collaborator Author

Closing to trigger a clean CI run. Will reopen.

@Jiachen0715 Jiachen0715 closed this Jul 9, 2026
@Jiachen0715 Jiachen0715 deleted the feat/DIARCHERS-1521-mcp-backend-fixes-and-write-ops branch July 9, 2026 09:36
@Jiachen0715 Jiachen0715 restored the feat/DIARCHERS-1521-mcp-backend-fixes-and-write-ops branch July 9, 2026 09:36
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.

1 participant