Chain three calls
When a workflow is a strict sequence - each step depends on the previous
one’s output - issuing N independent tools/call requests wastes round-trips
and exposes intermediate state. The mcp_pipeline meta-tool batches them into
one request, with {{step_id.path}} interpolation between steps.
Use case
Section titled “Use case”A community manager says: “Announce the office-hours session in #announcements, create a scheduled event for it, then give the host the ‘event-host’ role.”
Three calls. Each depends on the previous. Pipeline-shaped.
Tool flow
Section titled “Tool flow”-
Build the pipeline payload.
Each step has
id(for interpolation),tool(the tool name), andargs. Strings insideargsmay contain{{step_id.path}}placeholders. Below the announcement step’smessage_idflows into the event’s description. The host’s user ID and the role ID are known workflow inputs and are supplied directly to the role-grant step.{"name": "mcp_pipeline","arguments": {"steps": [{"id": "announce","tool": "messages_send","args": {"channel_id": "222233334444555566","content": "Office hours start in 30 minutes! React with :wave: to attend."}},{"id": "event","tool": "events_create","args": {"guild_id": "111122223333444455","name": "Office hours - January 1","scheduled_start_time": "2030-01-01T17:00:00Z","scheduled_end_time": "2030-01-01T18:00:00Z","entity_type": 3,"privacy_level": 2,"entity_metadata": { "location": "https://discord.com/channels/111122223333444455/222233334444555566/{{announce.message_id}}" },"description": "Linked to announcement {{announce.message_id}}"}},{"id": "grant","tool": "members_add_role","args": {"guild_id": "111122223333444455","user_id": "777788889999000011","role_id": "555566667777888899"}}]}} -
Read the response.
The pipeline returns
steps[]with per-step status,variables(the interpolation namespace at completion),total_duration_ms, andaborted.{"steps": [{"id": "announce","tool": "messages_send","status": "success","result": {"message_id": "888899990000111122","channel_id": "222233334444555566","jump_url": "https://discord.com/channels/111122223333444455/222233334444555566/888899990000111122","timestamp": "2030-01-01T16:30:00.000Z"},"duration_ms": 142},{"id": "event","tool": "events_create","status": "success","result": {"id": "333344445555666677","guild_id": "111122223333444455","name": "Office hours - January 1","description": "Linked to announcement 888899990000111122","scheduled_start_time": "2030-01-01T17:00:00.000Z","scheduled_end_time": "2030-01-01T18:00:00.000Z","status": 1,"entity_type": 3,"channel_id": null},"duration_ms": 218},{"id": "grant","tool": "members_add_role","status": "success","result": {"added": true,"user_id": "777788889999000011","role_id": "555566667777888899"},"duration_ms": 96}],"variables": {"announce": { "message_id": "888899990000111122", "channel_id": "222233334444555566" },"event": { "id": "333344445555666677", "name": "Office hours - May 1" },"grant": { "added": true, "user_id": "777788889999000011", "role_id": "555566667777888899" }},"total_duration_ms": 456,"aborted": false}{"steps": [{ "id": "announce", "tool": "messages_send", "status": "success", "duration_ms": 142 },{"id": "event","tool": "events_create","status": "error","error": { "code": "DISCORD_PERMISSION_DENIED", "message": "Missing MANAGE_EVENTS", "retriable": false },"duration_ms": 88}],"variables": { "announce": { "message_id": "888899990000111122" } },"total_duration_ms": 230,"aborted": true}Note that
grantis absent, not"skipped". On an abort the executor breaks out of the loop, so steps after the failing one are never dispatched and never appear insteps."skipped"is emitted only for a step whoseifcondition evaluated falsy.
Error handling
Section titled “Error handling”- Default abort-on-error. When a step returns an error, the pipeline sets
aborted: trueand stops immediately. Subsequent steps are not dispatched and do not appear insteps- the array simply ends at the failing step. The agent sees exactly which step blew up and what the partial state is. - Continue past errors. Set
continue_on_error: trueon a step to keep going. Use sparingly - it implies later steps must tolerate missing interpolation values. - Recursion guard. A step whose
toolismcp_pipelineis rejected up front with the error codePIPELINE_RECURSION. The pipeline aborts before running any step. - Limit. Pipelines cap at 20 steps. For larger workloads, split into multiple pipelines or use the dedicated bulk tool for that resource.
Why pipeline beats N separate calls
Section titled “Why pipeline beats N separate calls”| Concern | N separate tools/call | One mcp_pipeline |
|---|---|---|
| Round-trips | N | 1 |
| Stop after a failed step | client must re-implement | server-side, built in |
| Intermediate state | client juggles | exposed via variables |
| Audit logging | Depends on each tool’s idempotency metadata | One parent event plus events for non-idempotent leaves; idempotent leaves are skipped |
See also
Section titled “See also”mcp_pipeline- full step schema includingsave_asandif.messages_send,events_create,members_add_role- the three building blocks used in this recipe.- Recipe: bulk ban a raid - alternative pattern for parallelizable identical operations.
- Architecture: pipeline executor - how interpolation, abort, and variables work internally.