Flow Studio
Tool Call Node
The MCPToolCallNode — configuration, execution pattern, retry behaviour, and the MCPToolCallExecutor implementation that resolves servers, maps inputs, and captures tool results.
Node Configuration
{
"nodeType": "MCPToolCall",
"name": "analyzeDocument",
"config": {
"serverId": "bfai-document-ai",
"toolName": "analyze-document",
"inputMap": {
"documentUrl": "$output.fetchDocument.url",
"documentType": "$json.documentType",
"extractionSchema": {
"fields": ["invoiceNumber", "totalAmount", "currency", "vendorName"]
}
},
"timeoutSeconds": 60,
"retryCount": 2
}
}
Configuration Fields
| Field | Type | Required | Description |
|---|---|---|---|
serverId | string | Yes | Registered MCP server identifier from IMCPServerRegistry |
toolName | string | Yes | Tool name as declared in the server's tool catalog |
inputMap | object | Yes | Parameter map — keys are tool parameter names, values are expressions or literals |
timeoutSeconds | int | No | Per-call timeout in seconds (default: server-level timeout or 30s) |
retryCount | int | No | Number of retries on transient failure (default: 1; 0 = no retry) |
MCPToolCallExecutor — Implementation Pattern
public class MCPToolCallExecutor : BaseNodeExecutor<MCPToolCallSettings>
{
private readonly IMCPServerRegistry _registry;
private readonly IMCPClientFactory _clientFactory;
private readonly IExpressionEvaluator _expr;
public MCPToolCallExecutor(
IMCPServerRegistry registry,
IMCPClientFactory clientFactory,
IExpressionEvaluator expr)
{
_registry = registry;
_clientFactory = clientFactory;
_expr = expr;
}
protected override async Task<NodeExecutionResult> ExecuteAsync(
NodeExecutionContext ctx,
MCPToolCallSettings settings,
CancellationToken ct)
{
// 1. Resolve server definition
if (!_registry.TryGetServer(settings.ServerId, out var serverDef))
return NodeExecutionResult.Failure(
$"MCP server '{settings.ServerId}' is not registered.");
// 2. Evaluate inputMap expressions against current context
var toolParameters = new Dictionary<string, object?>();
foreach (var (paramName, expression) in settings.InputMap)
{
toolParameters[paramName] = expression is string s
? await _expr.EvaluateAsync(s, ctx, ct)
: expression; // literal object/array
}
// 3. Create authenticated MCP client (credentials resolved inside factory)
await using var client = await _clientFactory.CreateClientAsync(serverDef, ct);
// 4. Execute tool call with timeout
using var cts = CancellationTokenSource.CreateLinkedTokenSource(ct);
cts.CancelAfter(TimeSpan.FromSeconds(settings.TimeoutSeconds ?? serverDef.TimeoutSeconds));
var callId = Guid.NewGuid().ToString("N");
var callResult = await client.CallToolAsync(
settings.ToolName,
toolParameters,
cts.Token);
// 5. Return structured output
return NodeExecutionResult.Success(new
{
result = callResult.Content,
toolName = settings.ToolName,
serverId = settings.ServerId,
callId = callId,
executedAt = DateTimeOffset.UtcNow
});
}
}
Retry Behaviour
Retries apply only to transient failures: network errors, 429 Too Many Requests (with Retry-After respected), and 503/504 responses from the MCP server. Tool-level errors returned in the MCP response body (e.g., isError: true) are not retried — they surface immediately as node failure.
Tool name validation at design time: When a flow is saved in Flow Studio, the canvas fetches the tool catalog from
IMCPServerRegistry.GetToolsAsync(serverId) and validates that toolName exists. If the server is unreachable at design time, the canvas shows a warning but still allows saving. Runtime resolution is authoritative.
Timeout scope:
timeoutSeconds covers the entire round-trip from client request to tool response. It does not include the time to resolve credentials or establish the transport connection. Set generous timeouts for AI inference tools that may take 10–30 seconds.