feat(mcp-v2): add agent spawn tools#4076
Conversation
…s_create)
- New agents_run tool: launches an agent inside an existing workspace
(mirrors superset agents run / Workspaces.create({ agents }) per-entry).
- workspaces_create now accepts an optional agents[] for spawn-on-create,
matching the SDK's WorkspaceAgentLaunch shape. Tightened the response
type to the discriminated union the host already returns.
📝 WalkthroughWalkthroughAdds a new ChangesAgent Runtime Tool Registration
Workspace Creation with Agents
Sequence DiagramssequenceDiagram
actor Client as Client
participant MCP as MCP Server
participant Resolver as Workspace Resolver
participant Host as Host Service
Client->>MCP: agents_run(workspaceId, agent, prompt, attachmentIds)
MCP->>Resolver: getFromHost(workspaceId, organizationId)
alt Workspace Found
Resolver-->>MCP: { relayUrl, hostId, organizationId }
MCP->>Host: hostServiceMutation("agents.run",<br/>relayUrl, organizationId, hostId, jwt,<br/>workspaceId, agent, prompt, attachmentIds)
Host-->>MCP: { sessionId, label }
MCP-->>Client: { sessionId, label }
else Workspace Not Found
Resolver-->>MCP: null
MCP-->>Client: Error("Workspace not found")
end
sequenceDiagram
actor Client as Client
participant MCP as MCP Server
participant Host as Host Service
Client->>MCP: workspaces_create(name, description, agents?)
activate MCP
MCP->>MCP: Validate agents (if provided)<br/>using agentLaunchSchema
MCP->>Host: hostServiceMutation("workspaces.create",<br/>{ name, description, agents })
Host-->>MCP: { workspaceId, agents: [<br/>{ ok: true, sessionId, label } |<br/>{ ok: false, error }<br/>] }
deactivate MCP
MCP-->>Client: { workspaceId, agents }
Estimated Code Review Effort🎯 3 (Moderate) | ⏱️ ~25 minutes
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
Greptile SummaryThis PR adds agent spawning capabilities to the v2 MCP layer: a new Confidence Score: 3/5Mostly safe to merge, but One P1 finding in packages/mcp-v2/src/tools/agents/run.ts — response type needs the
|
| Filename | Overview |
|---|---|
| packages/mcp-v2/src/tools/agents/run.ts | New agents_run tool correctly resolves the workspace host before calling agents.run, but types the response as { sessionId; label } — omitting the { ok: false; error } failure branch the host RPC can return, leading to silently swallowed errors. |
| packages/mcp-v2/src/tools/workspaces/create.ts | Adds optional agents[] input param and tightens the response type from Array<unknown> to the correct discriminated union; pass-through to host is straightforward and consistent with existing patterns. |
| packages/mcp-v2/src/tools/register.ts | Simply imports and registers the new agentsRun tool in the existing registrar list; no issues. |
Sequence Diagram
sequenceDiagram
participant Client as MCP Client
participant Tool as agents_run tool
participant DB as v2Workspace.getFromHost
participant Relay as Host Relay
participant Host as Host Service
Client->>Tool: agents_run({ workspaceId, agent, prompt })
Tool->>DB: getFromHost({ organizationId, id: workspaceId })
DB-->>Tool: workspace (with hostId) | null
alt workspace not found
Tool-->>Client: Error: "Workspace not found"
else workspace found
Tool->>Relay: POST /hosts/{routingKey}/trpc/agents.run
Relay->>Host: agents.run({ workspaceId, agent, prompt })
Host-->>Relay: { ok: true, sessionId, label } OR { ok: false, error }
Relay-->>Tool: response
Note over Tool: ok:false not handled — error silently passed through
Tool-->>Client: { sessionId, label } (may be undefined if ok:false)
end
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 1
packages/mcp-v2/src/tools/agents/run.ts:41-63
**Missing failure discriminant in response type**
The `agents.run` host RPC can return `{ ok: false; error: string }` on business-logic failures (e.g. unknown agent preset), as evidenced by the discriminated union `workspaces_create` now uses for the same per-agent results. Typing the return here as only `{ sessionId: string; label: string }` means a `{ ok: false, error: "..." }` payload from the host passes through silently: the MCP client receives a wrong shape with `sessionId`/`label` as `undefined` and never sees the error message.
The response generic should mirror the union, and the `ok: false` branch should surface the error:
```typescript
return hostServiceMutation<
{ workspaceId: string; agent: string; prompt: string; attachmentIds?: string[] },
| { ok: true; sessionId: string; label: string }
| { ok: false; error: string }
>(
{ relayUrl: ctx.relayUrl, organizationId: ctx.organizationId, hostId: workspace.hostId, jwt: ctx.bearerToken },
"agents.run",
{ workspaceId: input.workspaceId, agent: input.agent, prompt: input.prompt, attachmentIds: input.attachmentIds },
).then((result) => {
if (!result.ok) throw new Error(result.error);
return result;
});
```
Reviews (1): Last reviewed commit: "feat(mcp-v2): add agent spawn tools (age..." | Re-trigger Greptile
| return hostServiceMutation< | ||
| { | ||
| workspaceId: string; | ||
| agent: string; | ||
| prompt: string; | ||
| attachmentIds?: string[]; | ||
| }, | ||
| { sessionId: string; label: string } | ||
| >( | ||
| { | ||
| relayUrl: ctx.relayUrl, | ||
| organizationId: ctx.organizationId, | ||
| hostId: workspace.hostId, | ||
| jwt: ctx.bearerToken, | ||
| }, | ||
| "agents.run", | ||
| { | ||
| workspaceId: input.workspaceId, | ||
| agent: input.agent, | ||
| prompt: input.prompt, | ||
| attachmentIds: input.attachmentIds, | ||
| }, | ||
| ); |
There was a problem hiding this comment.
Missing failure discriminant in response type
The agents.run host RPC can return { ok: false; error: string } on business-logic failures (e.g. unknown agent preset), as evidenced by the discriminated union workspaces_create now uses for the same per-agent results. Typing the return here as only { sessionId: string; label: string } means a { ok: false, error: "..." } payload from the host passes through silently: the MCP client receives a wrong shape with sessionId/label as undefined and never sees the error message.
The response generic should mirror the union, and the ok: false branch should surface the error:
return hostServiceMutation<
{ workspaceId: string; agent: string; prompt: string; attachmentIds?: string[] },
| { ok: true; sessionId: string; label: string }
| { ok: false; error: string }
>(
{ relayUrl: ctx.relayUrl, organizationId: ctx.organizationId, hostId: workspace.hostId, jwt: ctx.bearerToken },
"agents.run",
{ workspaceId: input.workspaceId, agent: input.agent, prompt: input.prompt, attachmentIds: input.attachmentIds },
).then((result) => {
if (!result.ok) throw new Error(result.error);
return result;
});Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/mcp-v2/src/tools/agents/run.ts
Line: 41-63
Comment:
**Missing failure discriminant in response type**
The `agents.run` host RPC can return `{ ok: false; error: string }` on business-logic failures (e.g. unknown agent preset), as evidenced by the discriminated union `workspaces_create` now uses for the same per-agent results. Typing the return here as only `{ sessionId: string; label: string }` means a `{ ok: false, error: "..." }` payload from the host passes through silently: the MCP client receives a wrong shape with `sessionId`/`label` as `undefined` and never sees the error message.
The response generic should mirror the union, and the `ok: false` branch should surface the error:
```typescript
return hostServiceMutation<
{ workspaceId: string; agent: string; prompt: string; attachmentIds?: string[] },
| { ok: true; sessionId: string; label: string }
| { ok: false; error: string }
>(
{ relayUrl: ctx.relayUrl, organizationId: ctx.organizationId, hostId: workspace.hostId, jwt: ctx.bearerToken },
"agents.run",
{ workspaceId: input.workspaceId, agent: input.agent, prompt: input.prompt, attachmentIds: input.attachmentIds },
).then((result) => {
if (!result.ok) throw new Error(result.error);
return result;
});
```
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/mcp-v2/src/tools/workspaces/create.ts (1)
27-44:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winEnforce
branch/prmutual exclusivity in code, not only docs.Line 26 declares “exactly one of
branchorpr”, but current validation allows both or neither. Add a guard before invokingworkspaces.createso invalid calls fail early with a clear tool-level error.Suggested patch
handler: async (input, ctx) => { + const hasBranch = typeof input.branch === "string" && input.branch.length > 0; + const hasPr = typeof input.pr === "number"; + if (Number(hasBranch) + Number(hasPr) !== 1) { + throw new Error("Provide exactly one of `branch` or `pr`."); + } + return hostServiceMutation<Also applies to: 67-113
🤖 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 `@packages/mcp-v2/src/tools/workspaces/create.ts` around lines 27 - 44, The inputSchema currently documents but does not enforce mutual exclusivity of branch and pr; add an explicit guard in the create handler (before calling workspaces.create) that checks the parsed payload from inputSchema: if both payload.branch and payload.pr are set, or if neither is set, throw/return a clear tool-level error (e.g., Error or a ValidationError) with a message like "exactly one of 'branch' or 'pr' must be provided"; place this check near where you call workspaces.create in create.ts so the invalid request fails fast and does not reach workspaces.create.
🧹 Nitpick comments (1)
packages/mcp-v2/src/tools/agents/run.ts (1)
12-30: ⚡ Quick winExtract the launch payload schema to a shared module to prevent drift.
agent/prompt/attachmentIdsvalidation now exists in bothagents_runandworkspaces_create. Centralizing it will keep tool contracts aligned as fields evolve.🤖 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 `@packages/mcp-v2/src/tools/agents/run.ts` around lines 12 - 30, The inputSchema block in run.ts duplicates validation for workspaceId, agent, prompt, and attachmentIds which is also defined in workspaces_create; extract these common validators into a shared module (e.g., export a LaunchPayloadSchema or individual Zod fragments) and replace the inline inputSchema with an import of that shared schema, ensuring you reuse the same definitions for workspaceId, agent, prompt, and attachmentIds to prevent drift and keep contracts aligned across agents_run and workspaces_create.
🤖 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.
Outside diff comments:
In `@packages/mcp-v2/src/tools/workspaces/create.ts`:
- Around line 27-44: The inputSchema currently documents but does not enforce
mutual exclusivity of branch and pr; add an explicit guard in the create handler
(before calling workspaces.create) that checks the parsed payload from
inputSchema: if both payload.branch and payload.pr are set, or if neither is
set, throw/return a clear tool-level error (e.g., Error or a ValidationError)
with a message like "exactly one of 'branch' or 'pr' must be provided"; place
this check near where you call workspaces.create in create.ts so the invalid
request fails fast and does not reach workspaces.create.
---
Nitpick comments:
In `@packages/mcp-v2/src/tools/agents/run.ts`:
- Around line 12-30: The inputSchema block in run.ts duplicates validation for
workspaceId, agent, prompt, and attachmentIds which is also defined in
workspaces_create; extract these common validators into a shared module (e.g.,
export a LaunchPayloadSchema or individual Zod fragments) and replace the inline
inputSchema with an import of that shared schema, ensuring you reuse the same
definitions for workspaceId, agent, prompt, and attachmentIds to prevent drift
and keep contracts aligned across agents_run and workspaces_create.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 1d84f799-a56f-4f37-9682-a05fbfb27f73
📒 Files selected for processing (3)
packages/mcp-v2/src/tools/agents/run.tspackages/mcp-v2/src/tools/register.tspackages/mcp-v2/src/tools/workspaces/create.ts
🧹 Preview Cleanup CompleteThe following preview resources have been cleaned up:
Thank you for your contribution! 🎉 |
…s_create) (#4076) - New agents_run tool: launches an agent inside an existing workspace (mirrors superset agents run / Workspaces.create({ agents }) per-entry). - workspaces_create now accepts an optional agents[] for spawn-on-create, matching the SDK's WorkspaceAgentLaunch shape. Tightened the response type to the discriminated union the host already returns.
Summary
v2 MCP previously had no way to spawn an agent — neither standalone nor as part of
workspaces_create— even though the CLI (superset agents run) and SDK (workspaces.create({ agents })) both support it. This wires both shapes through:agents_run(new) — launches an agent inside an existing workspace. Resolves the host that owns the workspace (samecaller.v2Workspace.getFromHostpattern used byworkspaces_delete), then calls hostagents.run. Mirrorssuperset agents run.workspaces_create— now accepts an optionalagents[]matching the SDK'sWorkspaceAgentLaunchshape (agent,prompt, optionalattachmentIds). Pass-through to the host's existingagentsparam. Also tightens the response type fromArray<unknown>to the discriminated union ({ ok: true, sessionId, label } | { ok: false, error }) the host already returns.Both tools target host RPCs (
agents.run,workspaces.create) that are already proven via CLI + SDK, so this is purely additive plumbing.Test plan
agents_runand the newagentsparam onworkspaces_createshow up in the tool list.agents_run(preset id, e.g.claude).agents: [{ agent: "claude", prompt: "..." }]and confirm the terminal session opens.workspaceIdtoagents_run→ "Workspace not found".Summary by cubic
Adds
agents_runand addsagents[]toworkspaces_createso MCP v2 can spawn agents in existing or new workspaces. Aligns with CLIsuperset agents runand SDKworkspaces.create({ agents }). No breaking changes.agents_run: resolves the workspace’s host and calls hostagents.run. Inputs:workspaceId,agent,prompt, optionalattachmentIds.workspaces_create: accepts optionalagents[]to spawn agents on create (same shape as SDK:agent,prompt, optionalattachmentIds).workspaces_createagentsresults to a discriminated union:{ ok: true, sessionId, label } | { ok: false, error }.Written for commit c8cadc9. Summary will update on new commits.
Summary by CodeRabbit