Skip to main content

MCP endpoint

The Load Balancer can optionally serve an MCP endpoint at /mcp, so that AI agents can call functions from selected groups/contracts as tools. The LB calls ordinary Worker /task endpoints, so Workers need no MCP configuration.

The protocol, authentication header, client setup and general limits are the same as for the Worker MCP endpoint. This page covers what is specific to the Load Balancer. The two endpoints and their configurations are independent.

Configure​

Set a distinct MCP_AUTH_KEY and the Worker credential references in your environment. MCP_AUTH_KEY must contain no whitespace and differ from LB_AUTH_KEY; otherwise MCP stays disabled and the Load Balancer logs a warning. Generate it with, for example, openssl rand -hex 32. The MCP key does not grant REST administration, logs or maintenance access.

MCP_AUTH_KEY=<random-agent-token>
DEFAULT_WORKER_AUTH_KEY=<AUTH_KEY-on-default-workers>

Create mcp.json next to the LB's package.json:

{
"targets": [
{
"group": "default",
"contract": 1,
"workerAuthKeyEnv": "DEFAULT_WORKER_AUTH_KEY",
"functions": ["hello"]
}
]
}

The Worker URLs remain in workers.json. Each target selects already discovered Workers. workerAuthKeyEnv names the environment variable that holds the AUTH_KEY of the target's Workers. All replicas in one group/contract must accept the referenced Worker key. A target key that matches MCP_AUTH_KEY or LB_AUTH_KEY is rejected as invalid configuration.

functions is optional and follows the same function selection rules as on a Worker: omit it for all discovered functions of the target, or use an empty array for none. An empty targets array exposes no tools. Duplicate group/contract entries, unknown fields and missing referenced secrets are rejected. This selection is independent of any Worker's own MCP allowlist.

mcp.json reloads without a restart, as described in Live configuration. Set MCP_CONFIG_PATH to use another location (relative to the application root, or absolute). Referenced Worker keys, like the MCP token, are read from the environment at startup: restart to rotate them.

Connect an agent​

Connect an agent to https://lb.example.com/mcp with MCP_AUTH_KEY, using the client configuration examples with the LB URL. The agent does not need LB_AUTH_KEY or x-wr-auth: the LB derives routing from the selected tool and resolves Worker keys server-side.

LB tool names combine group, contract, function and a stable short hash. For example, a name begins with web_v1_fetchHtml_. The suffix avoids collisions when groups or function names normalize to the same characters. Use the exact name returned by the MCP tool catalog rather than constructing it.

The agent supplies only the function's input parameters. It cannot override the group, contract, Worker credential, delivery mode or priority.

Docker​

mkdir -p .mcp
cp mcp.example.json .mcp/mcp.json
docker compose -f docker-compose.yml -f docker-compose.mcp.yml up --build

The optional override loads .env, including the custom Worker key variables, and mounts the configuration directory read-only. Editing .mcp/mcp.json updates MCP live. Changing environment secrets requires recreating the container.

Monitor​

The dashboard's MCP panel needs no token and shows the endpoint, enabled state, tool titles and availability. Use authenticated GET /health with LB_AUTH_KEY for selected groups/contracts, exact tool names, input schemas, Worker availability and configuration errors. The MCP-only token receives public health information only. Worker keys and the names of their environment variables are not returned in tool catalogs, health metadata or the dashboard.

The catalog is generated from discovered functions. A saturated Worker can remain listed as ready; calls wait for a matching slot without consuming an execution attempt and fail if their deadline expires.

In addition to the common troubleshooting cases, check the target group/contract when the catalog is empty, Worker connectivity when a tool is unavailable, and the referenced Worker credentials when tasks fail.

Timeouts and retries​

MCP jobs use the same BullMQ queue as REST tasks, with one attempt: the Load Balancer does not retry MCP calls, to avoid automatically duplicating side effects. Waiting for a busy target does not consume an execution attempt.

Calls are synchronous and wait up to the LB's TASK_TIMEOUT (default 300 s). Many MCP clients give up after about 60 s; the Worker still finishes the call, but the result is discarded.

A function's own maxRetries applies to ordinary failures, never to function timeouts; configure write operations accordingly. A function deadline aborts its context.signal, while the Worker keeps its slot until the handler settles. LB and client deadlines and disconnections do not send cancellation to the Worker. See cooperative cancellation and the general MCP limits.