Foundations

Why Multiple Specialized Agents Beat One Generalist

⏱ 14 min

Course 3 ended with one working assistant: a single MCP server, a handful of abilities, one agent that could plan a multi-step task on its own. It’s tempting to keep growing that one agent forever, adding abilities as new needs come up, until it can do almost anything on your site. This lesson argues that’s usually the wrong instinct once a site has genuinely different audiences to serve, and shows what “more than one agent” actually looks like when you build it out of the primitives you already have.

What you'll learn in this lesson
What a "generalist" agent costs as it grows
Wider permission scope, muddier tool descriptions, harder debugging, all compounding together.
The three real benefits of narrower agents
Tighter permission scopes, clearer ability descriptions, and easier debugging, backed by mechanisms you already have.
How a server boundary becomes an agent boundary
Reusing McpAdapter::create_server() from Course 2 and Course 8 to give each role its own tool list.
The running example this course builds on
A customer-facing support agent and an internal fulfillment agent, introduced here and extended in every later lesson.
Prerequisites

Course 3 completed, so you’re comfortable with a connected client, permission callbacks, and multi-step tool chaining. Familiarity with McpAdapter::create_server() from Course 2 or Course 8 helps, since Step 3 reuses it directly, but this lesson explains enough of it to follow along either way.

Step 1: What “multi-agent” means here, honestly

There is no WordPress “Multi-Agent API.” What this course calls an agent is just: one MCP server, exposing one deliberately scoped set of abilities, typically connected to by one kind of client or user. Two agents means two servers, each with its own ability list and its own transport permission callback, both registered inside the same mcp_adapter_init callback, the exact mechanism Course 2 introduced and Course 8 went deep on. Nothing new is being invented in this course, the pattern is entirely in how you choose to split abilities across servers and design the abilities that let those servers coordinate.

Step 2: What one generalist agent quietly costs you

A single server exposing every ability on your site to every client works fine at first. It gets worse in three specific, compounding ways as the ability list grows.

The generalist-agent tax
ProblemWhy it happens
Wide permission scopeOne transport permission callback has to be loose enough to admit every legitimate caller, a customer-facing chat widget and an internal admin tool end up sharing the same bar for entry.
Muddier ability descriptionsA model choosing among thirty abilities from every part of the site has far less context to disambiguate two similarly named tools than a model choosing among five abilities that all belong to one clear role.
Harder debuggingWhen something goes wrong, “which agent, doing what, called which ability” is genuinely unclear if every caller shares one server and one ability list, you’re reading one merged log instead of one log per role.

None of these are fatal on a small site with two or three abilities. They become real operational pain once an ability list grows past a dozen entries serving more than one kind of caller, which is exactly the point where teams reach for this course’s patterns.

Step 3: A server boundary as an agent boundary

The running example for the rest of this course is a small support-and-fulfillment system. A customer-facing chat agent should be able to look up an order’s status and open an escalation. An internal fulfillment agent, used only by staff tooling, should be able to actually process a return or reship an order. Those are two different trust levels and two different tool sets, so they become two servers:

// File: order-ops.php
add_action( 'mcp_adapter_init', function ( $adapter ) {

	// Customer-facing: narrow, read-mostly, safe for a public chat widget.
	$adapter->create_server(
		'order-ops-support-server',
		'order-ops/support',
		'mcp',
		'Order Ops Support Server',
		'Read-only order lookup and escalation-opening abilities for customer chat.',
		'v1.0.0',
		array( \WP\MCP\Transport\HttpTransport::class ),
		\WP\MCP\Infrastructure\ErrorHandling\ErrorLogMcpErrorHandler::class,
		\WP\MCP\Infrastructure\Observability\NullMcpObservabilityHandler::class,
		array(
			'order-ops/get-order-status',
			'order-ops/open-escalation',
		),
		array(),
		array(),
		function () {
			return true; // gated by your own API key or session check, not staff capabilities
		}
	);

	// Internal-only: the abilities that actually change fulfillment state.
	$adapter->create_server(
		'order-ops-fulfillment-server',
		'order-ops/fulfillment',
		'mcp',
		'Order Ops Fulfillment Server',
		'Staff-only abilities for processing returns and reshipping orders.',
		'v1.0.0',
		array( \WP\MCP\Transport\HttpTransport::class ),
		\WP\MCP\Infrastructure\ErrorHandling\ErrorLogMcpErrorHandler::class,
		\WP\MCP\Infrastructure\Observability\NullMcpObservabilityHandler::class,
		array(
			'order-ops/process-return',
			'order-ops/reship-order',
		),
		array(),
		array(),
		function () {
			return current_user_can( 'manage_woocommerce' ) || current_user_can( 'edit_shop_orders' );
		}
	);
} );

The support agent’s tool list has exactly two entries in it. It cannot call order-ops/reship-order even if a compromised or careless client tried, that ability isn’t on this server at all. The fulfillment agent’s tool list is equally narrow in the other direction. Each server’s permission callback only has to answer one question for one audience, not a compromise question for both at once.

Step 4: Narrower tool sets make descriptions do less work

With only two abilities on the support server, order-ops/get-order-status’s description doesn’t need to explain how it differs from five other order-related tools, there aren’t five others in view. Compare the mental load a model faces:

Generalist server (30 abilities): "is this the order lookup for staff, or for
customers, or the one that also triggers a refund?"

Support server (2 abilities): "there are two tools here, one reads status,
one opens an escalation. The task is asking about status."

This isn’t a claim that models can’t handle large tool lists, capable clients often manage just fine. It’s that a smaller, role-scoped list removes an entire class of ambiguity before the model ever has to resolve it, and removes it structurally rather than through a better-written description.

Test it

Register both servers from Step 3, then confirm the split actually holds:

# File: terminal
wp mcp-adapter list --format=table

Connect a client to order-ops-support-server and confirm tools/list returns only the two support abilities. Then connect as a staff user to order-ops-fulfillment-server and confirm it returns only the two fulfillment abilities, and that connecting as a non-privileged user to that second server is rejected outright by its transport_permission_callback, not merely by an individual ability’s own check.

Splitting agents isn't free, and this course will say so again

Two servers means two things to register, two permission callbacks to keep correct, and two places to look when debugging a caller’s behavior. That tradeoff is worth it once a generalist agent’s tool list has genuinely mixed audiences or trust levels. It is not automatically worth it for every site, and the final lesson in this course comes back to exactly where that line sits.

Recap

A “specialized agent” in this course is just an MCP server with a narrow, role-scoped ability list and its own transport permission callback, both built with the same McpAdapter::create_server() call Course 2 and Course 8 already covered. Splitting a growing generalist server into role-scoped ones tightens permission scope, sharpens ability descriptions by shrinking the set a model has to disambiguate, and makes debugging a specific role’s behavior easier since its calls aren’t mixed with every other caller’s. The support-and-fulfillment example from Step 3 carries through the rest of this course.

Resources & further reading

Planner/Executor Patterns With Abilities →