callTool method
Call a tool on the server
Every request method takes an optional meta, sent as the request
_meta. It carries application context the server reads per request
(e.g. a forwarding host relaying its caller's identity); use namespaced
keys (prefix/name). Reserved io.modelcontextprotocol/* keys the
client writes on the stateless path always win.
Implementation
Future<CallToolResult> callTool(
String name,
Map<String, dynamic> toolArguments, {
Map<String, dynamic>? meta,
RequestOptions? options,
}) async {
if (!_initialized) {
throw McpError('Client is not initialized');
}
if (!_statelessMode && _serverCapabilities?.tools != true) {
throw McpError('Server does not support tools');
}
// Create a clean params map with properly typed values
final Map<String, dynamic> params = _withMeta({
'name': name,
'arguments': Map<String, dynamic>.from(toolArguments),
}, meta);
if (_mirrorsParamHeaders) {
if (!_toolParamHeaders.containsKey(name)) await listTools();
try {
return await _callToolOnce(name, params, options);
} on McpError catch (e) {
if (e.code != McpProtocol.errorHeaderMismatch) rethrow;
// The tool's annotations may have changed: read them again, retry.
_toolParamHeaders.remove(name);
await listTools();
return _callToolOnce(name, params, options);
}
}
// 2025-11-25: a tool that runs only as a task is always called as one.
if (!_statelessMode && _serverToolTasks && _toolTaskSupport[name] == 'required') {
final task = await callToolAsTask(name, toolArguments, meta: meta, options: options);
final result = CallToolResult.fromJson(await taskResult(task.taskId, options: options));
_checkToolOutput(name, result);
return result;
}
return _callToolOnce(name, params, options);
}