MCP authoring guide
What an MCP server needs to look like to play well with PipedAI triggers.
PipedAI is the orchestrator and ledger; your MCP is where the work happens. Every trigger points at one MCP URL with one set of headers. When the worker fires the trigger, it generates a per-run MCP config, invokes claude -p against your prompt, and Claude calls into your MCP tools to do the actual work and write results.
The contract
- HTTP MCP server reachable from the worker host. Streamable HTTP transport (Anthropic's standard) is what
claude -p --mcp-configspeaks. - Service-token auth via the Authorization header (or any fixed-name header). The header value is what you put into the trigger's MCP headers JSON.
- Idempotent or guarded tools. Triggers can fire multiple times (cron, retries) — design tools to either be idempotent or to detect and skip duplicates.
The MCP headers JSON
On the trigger editor, the “MCP headers (JSON)” field takes a flat object of string→string. Every entry is added to the request headers when Claude calls the MCP. The shape is whatever your MCP expects; the most common is an Authorization Bearer:
json{
"Authorization": "Bearer service-token-xxxxx"
}Other common patterns:
json{
"x-api-key": "service-token-xxxxx",
"x-tenant": "acme-prod"
}hasMcpHeaders: true, never the values.Service-token pattern
Marolence MCPs follow the convention /automated/<mcp_name>/mcp with a service token issued by the MCP's own backoffice. Generate one per-trigger so you can revoke it surgically without touching unrelated triggers.
Token rotation
On the trigger editor, the “Rotate token” button opens a dialog for new headers. Behind the scenes it calls POST /api/v1/triggers/:id/rotate-mcp-token which is admin+ only and audited as a separate mcp-token.rotated action. The new headers take effect on the next run; in-flight runs continue with the old.
Authoring the prompt
The prompt is plain English with full access to the MCP tools. Standard guidance:
- State the goal explicitly. “Process the queue and write results back via
create_record.” - Reference tool names where useful so Claude has concrete handles.
- For cases where there's no work, instruct Claude to say so explicitly — PipedAI captures the final assistant message into
shortMessageon the run record. - For unrecoverable errors, have the prompt emit
[error: …]in the assistant text. The worker's fault classifier picks that up and tags the run as a client fault, which suppresses auto-retry.
Payload templating (on-demand)
Triggers fired via POST /triggers/:id/run can carry a JSON payload. The worker substitutes {{payload}} and {{payload.foo.bar}} tokens into the prompt before invoking claude -p. Useful for webhook-driven triggers where the inbound event determines what Claude works on.
Notify downstream systems on completion
For MCPs that need to react to run outcomes (Slack notifications, downstream queues, billing events), set the trigger's webhookUrl + webhookSecret on the trigger editor. PipedAI POSTs an HMAC-SHA256-signed JSON body to that URL on every terminal Run transition (succeeded / failed / timed_out). See the completion webhooks guide for payload shape, retry semantics, and verification samples in Node, Python, and Ruby.