API surface — MCP tools, REST endpoints, and coverage
The current catalog of MCP tools and REST endpoints exposed by the Studio Host, plus which surface (the VS Code extension, autonomous agents, or neither) actually reaches each one. Ground truth (verified directly against source, not the tables below — the tables illustrate shape/category, not an exhaustive per-tool listing): 117nm_v1_* MCP
tools, 72 of them dispatched in-process to autonomous agents, 15 nms_v1_*
external-caller tools, and 214 REST routes.
Frozen design principles, request/response schemas, and the error envelope format
live in the internal MCP v1 contract — this page is the practical, currently-verified
catalog and supersedes tool counts anywhere they’ve drifted.
External caller surface (nms_v1_*)
These 15 tools are the recommended entry point for external MCP clients — Claude
Code, Cursor, scripts, CI agents. They cover the full human-in-the-loop lifecycle at
a goal-centric level, without requiring knowledge of work units, branches, or the
internal DAG.
Naming:
nms_v1_* (NodalMerge Studio v1) vs. nm_v1_* (NodalMerge v1). The
extra s marks the Studio-level abstraction layer. Both namespaces share the same
host and the same error envelope format.Goal management
Clarifications
Results
Repository registration
Workspace / feedback
Typical external-caller flow
/studio/goals,
/studio/merges, /studio/repositories, /studio/clarifications), but the
nms_v1_* MCP surface is the preferred path for MCP-native clients.
How the transports relate
MCP tool catalog (117 tools — categories below are not exhaustive)
✅ = dispatched in-process to orchestrator/worker agents · — = MCP-client, REST, or extension only.Projection
Work unit
Task
Branch
Merge
Dead-letter
Deliberately not dispatched to orchestrator/worker agents — these are
human-initiated recovery actions on an already-failed, already-exited work unit, not
something a running agent would ever call on itself. The recommended external-caller
flow reaches the same capability through
nms_v1_goal_status (surfaces an unresolved
failure and which actions apply) and nms_v1_goal_recover (resolves the goal’s own
latest entry internally — no entry ID needed) instead of these detailed,
entry-ID-based tools.Replay
State / Known Good
Snapshot
Agent
Agents cannot pause/resume themselves or each other — those are human/extension-only
actions today.
Workspace — file I/O, execution, semantic navigation, and profile
Routing rule: when semantic tools are allowed in a profile, they are the authoritative
path for symbol definition/reference/implementation questions. Use
nm_v1_workspace_search for text/content questions, not symbol relationship
resolution.
Scheduler
Intent
Artifact
Goal, Decision, Evidence, Trajectory, Hypothesis (Phase 6.7+)
None of these are dispatched to autonomous agents yet.
Phase 7 — REST-only, no MCP tool at all
REST endpoint catalog (214 routes)
Grouped by resource area;StudioRestEndpoints.cs is the single file that registers
all of these.
Workspace files & execution
branchId is a query parameter on every one of these, not a route segment — branch
IDs like merge/{workUnitId} contain a literal /, which a {branchId} route
segment can never match.
POST /studio/workspace/build|test|exec|run?branchId=...— trigger build / test / build+test+lint / run on a branchPOST /studio/workspace/run/stop?branchId=...— stop one/all branch run processesGET /studio/workspace/exec/latest?branchId=...— latest execution resultGET /studio/workspace/exec/output?branchId=...&resultId=...— cached stdout/stderr for a past resultGET /studio/workspace/path?branchId=...— branch working directory pathGET /studio/workspace/profile?branchId=...— detected workspace roots/stacks/commandsPOST /studio/workspace/profile/rescan?branchId=...— refresh detected workspace profilePOST /studio/workspace/switch— force a repository resync against current disk content (see Guides → Repository virtualization)
Work units, tasks, agents, merges, branches
- Work units:
GET/POST /studio/workunits,GET /studio/workunits/{id}(+/children,/artifacts,/orchestration-events,/intents,/conflict-report,/proposal-dag),POST /studio/workunits/{id}/cancel,POST /studio/workunits/{id}/requeue(un-cancel and resume; optional credential overrides),POST /studio/stop-all - Tasks:
GET /studio/tasks,GET /studio/tasks/{id},POST /studio/tasks,PUT /studio/tasks/{id},POST /studio/tasks/{id}/assign - Agents:
GET /studio/agents(?all=truefor all),POST /studio/agents/spawn,GET /studio/agents/{id}/status,POST /studio/agents/{id}/pause|resume|stop - Merges:
GET/POST /studio/merges,GET /studio/merges/{id}(+/constituents,/file-changes),POST /studio/merges/{id}/validate|review|apply(reviewbody:{ decision: "Approved"|"Rejected" }— there is no separate/accept//rejectroute),GET /studio/merges/compare?ids=,POST /studio/merges/{id}/branch,POST /studio/merges/{id}/restore-workspace - Branches:
GET /studio/branches,POST /studio/branches,POST /studio/branches/{id}/checkout,GET /studio/branches/{id}/status,POST /studio/branches/candidate/promote - Candidate & task conflicts (reconciliation — see
Concepts → Trust & autonomy § Reconciling candidate conflicts):
GET /studio/branches/candidate/conflicts,POST /studio/branches/candidate/conflicts/{id}/reconcile,POST /studio/branches/candidate/conflicts/{id}/resolve,GET /studio/workunits/{id}/task-conflicts,POST /studio/workunits/{id}/task-conflicts/{conflictId}/reconcile,POST /studio/workunits/{id}/task-conflicts/{conflictId}/resolve. The work unit’s own/proposal-dag(listed above) now also surfaces reconciliation edges, andGET /studio/merges/{id}/constituentsresolves a reconciled proposal back to its source proposals.
Known-good states & cache management
POST /studio/state/markKnownGood,GET /studio/state/knownGood/{branchId},POST /studio/state/checkoutKnownGood,POST /studio/state/{stateId}/fork(fork a new work unit seeded from a checkpoint’s snapshot branch — the extension’s “Fork from Known Good”)- Branch directory cache (
WorkspaceCacheManager, REST-only — see Guides → Repository virtualization):POST /studio/cache/evict?workUnitId=...,POST /studio/cache/materialize?workUnitId=...,POST /studio/cache/evict/orphaned,POST /studio/cache/gc?dryRun=...
Dead-letter queue
GET /studio/dead-letter,GET /studio/dead-letter/{id},GET /studio/dead-letter/by-work-unit/{workUnitId},GET /studio/dead-letter/history/{workUnitId}(full failure history, oldest first)POST /studio/dead-letter/{id}/retry,POST /studio/dead-letter/{id}/retry-with-context(folds a human correction into the goal, bypasses the normal attempt cap),POST /studio/dead-letter/{id}/replan(decompose the failed slice into fresh sub-slices, mark originalCancelled— never gated on attempt count since it never resumes the failed work unit),POST /studio/dead-letter/{id}/continue(MaxIterationsExceededonly — resume the SAME work unit with reconstructed prior context and a fresh iteration budget)
Everything else
- Agent profiles:
GET /studio/agent-profiles,GET /studio/agent-profiles/{id},POST/PUT /studio/agent-profiles/{id} - Scheduler:
GET /studio/scheduler/pending|awaiting-resume,POST /studio/scheduler/{workUnitId}/resume,POST /studio/scheduler/resume-all,POST /studio/scheduler/enqueue - Clarifications:
GET /studio/clarifications/awaiting,POST /studio/clarifications/request,POST /studio/clarifications/{workUnitId}/respond - Sessions & events:
GET/POST /studio/sessions,GET /studio/sessions/{id},POST /studio/sessions/{id}/pause|resume|abandon,GET /studio/sessions/{id}/workunits|events|state,GET /studio/events/{id} - Artifacts:
GET/POST /studio/artifacts,GET /studio/artifacts/{id}(+/children),POST /studio/artifacts/{id}/elevate(widen a repo-scoped constraint to all repositories) - Insights & findings (see
Guides → Knowledge & constraints):
GET /studio/findings(?status=),POST /studio/findings/{id}/review({ decision, notes }— promote/dismiss/investigating),POST /studio/findings/import,POST /studio/insights/detect-findings(deterministic pattern rules),POST /studio/insights/llm-scan(body is a resolved LLM config; routes to an HTTP one-shot or aclaude-cli/codex-clione-shot by provider; returns{ findings, rawCliOutput }) - Constraints:
GET /studio/constraints(?repositoryId=; each row labeled with reach +appliesToAllRepos+ localenabled),POST /studio/constraints(manual add —{ title, body, reach: "Workgroup"|"Private", repoSpecific }→ a global constraint at the chosen 2×2 scope),POST /studio/constraints/{id}/toggle({ disabled }— peer-private local suppression, not replicated),POST /studio/constraints/{id}/scope({ reach, repoSpecific }— set the full 2×2 scope and re-route; generalizes/elevate),GET /studio/constraints/proposed(work-unit-owned observer/agent constraints eligible for promotion, each flaggedpromoted),POST /studio/constraints/{id}/promote({ reach?, repoSpecific? }— mint a global copy of a lineage constraint stamped withpromotedFromArtifactId; idempotent, returns the existing promotion if already promoted) - Options/policies/projections/snapshots:
GET/POST /studio/options,GET /studio/policies,GET /studio/projections,GET /studio/projections/{type},GET /studio/snapshots/{agentId}(+/compare/{otherAgentId}) - Replay:
GET /studio/replay/timeline(+/{branchId}),GET /studio/replay/range/{branchId},POST /studio/replay/rollback/{branchId},GET /studio/replay/inspect/{branchId} - Goals/decisions/evidence/trajectory/hypotheses/reasoning/models:
GET/POST /studio/goals,GET/POST /studio/decisions,GET /studio/evidence+POST /studio/evidence/attach,GET /studio/trajectory/replay+POST /studio/trajectory,GET /studio/hypotheses+POST /studio/hypotheses/fork,POST /studio/reasoning,GET /studio/models/compare|replay/{workUnitId} - Phase 7:
GET/POST /studio/experiments,GET /studio/experiments/{id},POST /studio/steering/redirect|fork-from-node,POST /studio/counterfactuals