Tools as durable activities
Register an MCP server and its tools become checkpointed workflow activities: retried on failure, replayed from cache after a crash.
The situation
A workflow needs a classifier that lives behind an MCP server. Calling it directly from workflow code means handling retries, partial failures and a process that crashes mid-call. The tool protocol itself guarantees none of that.
The recipe
import { Durable } from '@hotmeshio/hotmesh';import { McpClient, type LTEnvelope } from '@hotmeshio/long-tail';
const tools = await McpClient.toolActivities(serverId);const { mcp_doc_analyzer_classify } = Durable.workflow.proxyActivities<typeof tools>({ activities: tools, retry: { maximumAttempts: 3 },});
export async function classifyDocument(envelope: LTEnvelope) { const result = await mcp_doc_analyzer_classify({ content: envelope.data.content }); if (result.confidence >= 0.85) return { type: 'return', data: result }; return { type: 'escalation', data: result, message: 'Low confidence', role: 'reviewer' };}Tool names derive from the server and tool: mcp_{serverName}_{toolName}, with non-alphanumeric characters replaced by underscores. The call reads like a function call; it is also an MCP tool call and a durable activity.
The guarantee
The result is checkpointed to Postgres. If the process crashes between the tool call and its checkpoint, the workflow replays from cache and the external server is not called a second time: exactly-once semantics over a protocol that does not provide them. The activity carries the workflow’s identity, so the tool acts as the run’s principal. See MCP.
Related patterns
Agents and MCP
Humans as tools
An agent routes work to a person through the same tool protocol it uses for everything else, and gets the typed answer back.
Agents and MCP
A workflow is a tool
A compiled pipeline deploys as an MCP tool, so the next agent that meets the same case calls a deterministic fix instead of reasoning again.
The escalation boundary
Confidence-gated escalation
The workflow finishes on its own when the model is confident and parks a review row when it is not, so people see only the uncertain cases.
