Skip to content

feat(mcp-v2): add agent spawn tools#4076

Merged
saddlepaddle merged 1 commit intomainfrom
add-spawn-agent-mcp
May 5, 2026
Merged

feat(mcp-v2): add agent spawn tools#4076
saddlepaddle merged 1 commit intomainfrom
add-spawn-agent-mcp

Conversation

@saddlepaddle
Copy link
Copy Markdown
Collaborator

@saddlepaddle saddlepaddle commented May 5, 2026

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 (same caller.v2Workspace.getFromHost pattern used by workspaces_delete), then calls host agents.run. Mirrors superset agents run.
  • workspaces_create — now accepts an optional agents[] matching the SDK's WorkspaceAgentLaunch shape (agent, prompt, optional attachmentIds). Pass-through to the host's existing agents param. Also tightens the response type from Array<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

  • Reconnect to v2 MCP and verify agents_run and the new agents param on workspaces_create show up in the tool list.
  • Spawn an agent into an existing workspace via agents_run (preset id, e.g. claude).
  • Create a workspace with agents: [{ agent: "claude", prompt: "..." }] and confirm the terminal session opens.
  • Verify error path: pass a bogus workspaceId to agents_run → "Workspace not found".

Summary by cubic

Adds agents_run and adds agents[] to workspaces_create so MCP v2 can spawn agents in existing or new workspaces. Aligns with CLI superset agents run and SDK workspaces.create({ agents }). No breaking changes.

  • New Features
    • New agents_run: resolves the workspace’s host and calls host agents.run. Inputs: workspaceId, agent, prompt, optional attachmentIds.
    • workspaces_create: accepts optional agents[] to spawn agents on create (same shape as SDK: agent, prompt, optional attachmentIds).
    • Tightened response typing for workspaces_create agents results to a discriminated union: { ok: true, sessionId, label } | { ok: false, error }.

Written for commit c8cadc9. Summary will update on new commits.

Summary by CodeRabbit

  • New Features
    • New agent execution tool allows running agents with custom prompts and optional attachments.
    • Workspace creation now supports launching agents automatically during workspace setup.

…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.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 5, 2026

📝 Walkthrough

Walkthrough

Adds a new agents_run MCP tool that launches agents in a workspace by resolving workspace context and delegating to the host service. Concurrently extends the workspaces_create tool to accept an optional agents parameter, enabling workspace creation with immediate agent spawning.

Changes

Agent Runtime Tool Registration

Layer / File(s) Summary
Core Implementation
packages/mcp-v2/src/tools/agents/run.ts
New register(server) function defines the agents_run MCP tool with input validation (workspaceId, agent, prompt, optional attachmentIds). Handler resolves workspace via caller.v2Workspace.getFromHost, throws if not found, then calls hostServiceMutation on "agents.run" endpoint with workspace credentials and request payload, returning { sessionId, label }.
Tool Wiring
packages/mcp-v2/src/tools/register.ts
Imports ./agents/run module and adds agentsRun to the REGISTRARS array so the tool is registered when registerTools runs.

Workspace Creation with Agents

Layer / File(s) Summary
Schema Definition
packages/mcp-v2/src/tools/workspaces/create.ts
Introduces agentLaunchSchema Zod validator for agent entries (required agent and prompt, optional attachmentIds). Extends workspaces_create input schema with optional agents parameter as an array of validated agent launch specs.
Request & Response Types
packages/mcp-v2/src/tools/workspaces/create.ts
Updates hostServiceMutation type declarations to include agents in the request payload and restructures the response to expect agents as an array of discriminated results (success with sessionId/label or failure with error).
Mutation Call
packages/mcp-v2/src/tools/workspaces/create.ts
Passes agents: input.agents in the hostServiceMutation("workspaces.create", ...) payload, forwarding agent specifications to the host service.

Sequence Diagrams

sequenceDiagram
    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
Loading
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 }
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~25 minutes


🐰 A hop, a tool, a workspace anew,
Agents dance in the MCP stew,
Launch them at creation's dawn,
Schema guards from dusk to morn,
Hop, hop, hooray—agents run! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main feature addition of two agent spawn tools to the MCP v2 module.
Description check ✅ Passed The PR description comprehensively covers the changes, objectives, and includes a detailed test plan addressing key functionality and error paths.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch add-spawn-agent-mcp

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 5, 2026

Greptile Summary

This PR adds agent spawning capabilities to the v2 MCP layer: a new agents_run tool and an optional agents[] parameter on workspaces_create. The workspaces_create changes are clean, but agents_run has a P1 type mismatch on its response that silently swallows host-side errors.

Confidence Score: 3/5

Mostly safe to merge, but agents_run will silently swallow host-side agent errors due to the missing ok: false branch in the response type.

One P1 finding in agents_run: the response type omits the failure discriminant, so business-logic errors from agents.run are not surfaced to the caller. The workspaces_create changes are clean. Score is held to 3 given the real defect on the new tool's core path.

packages/mcp-v2/src/tools/agents/run.ts — response type needs the { ok: false; error } discriminant handled

Important Files Changed

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
Loading
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

Comment on lines +41 to +63
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,
},
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 win

Enforce branch/pr mutual exclusivity in code, not only docs.

Line 26 declares “exactly one of branch or pr”, but current validation allows both or neither. Add a guard before invoking workspaces.create so 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 win

Extract the launch payload schema to a shared module to prevent drift.

agent/prompt/attachmentIds validation now exists in both agents_run and workspaces_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

📥 Commits

Reviewing files that changed from the base of the PR and between 2ea3ce4 and c8cadc9.

📒 Files selected for processing (3)
  • packages/mcp-v2/src/tools/agents/run.ts
  • packages/mcp-v2/src/tools/register.ts
  • packages/mcp-v2/src/tools/workspaces/create.ts

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 5, 2026

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ✅ Neon database branch

Thank you for your contribution! 🎉

@saddlepaddle saddlepaddle merged commit 1369b42 into main May 5, 2026
17 checks passed
saddlepaddle added a commit that referenced this pull request May 6, 2026
…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.
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