screenpipe/screenpipe · error · Error
tool is required
Error message
tool is required
What it means
Same tool as errorIndex 58: after server_id validation, it requires a non-empty `tool` name identifying which MCP tool to invoke on that server. Empty/whitespace tool names throw this error before the POST to /mcp-servers/{id}/call.
Source
Thrown at crates/screenpipe-core/assets/acp/screenpipe-tools.mjs:963
inputSchema: {
type: "object",
properties: {
server_id: { type: "string", description: "The MCP server id (from sp_mcp_list_tools or list_connections)." },
tool: { type: "string", description: "The tool name advertised by that server." },
arguments: {
type: "object",
description: "JSON arguments matching the tool's parameter schema.",
additionalProperties: true,
},
},
required: ["server_id", "tool"],
additionalProperties: false,
},
async run(args) {
const serverId = String(args?.server_id ?? "").trim();
const tool = String(args?.tool ?? "").trim();
if (!serverId) throw new Error("server_id is required");
if (!tool) throw new Error("tool is required");
const res = await fetch(`${apiBase()}/mcp-servers/${encodeURIComponent(serverId)}/call`, {
method: "POST",
headers: mcpBridgeHeaders(),
body: JSON.stringify({ tool, arguments: args?.arguments ?? {} }),
});
const bodyText = await res.text();
if (!res.ok) {
throw new Error(`sp_mcp_call failed (${res.status}): ${bodyText.slice(0, 800)}`);
}
// The engine wraps the raw MCP result as { data: { content, isError? } }.
// Return the inner result so the agent sees content and any isError flag;
// if the tool itself errored (isError=true, HTTP still 200), surface it.
let parsed;
try {
parsed = JSON.parse(bodyText);
} catch {
return JSON.stringify({ content: [{ type: "text", text: bodyText.slice(0, 4000) }] });
}View on GitHub (pinned to 4ebf712990)
Solutions
- Run sp_mcp_list_tools for the server_id and copy the exact tool name.
- Trim the tool string before calling.
- Put per-tool parameters under `arguments` (defaults to {}), not as top-level fields.
Example fix
// before
mcpCallTool({ server_id: "composio-abc123", tool: " " })
// after
mcpCallTool({ server_id: "composio-abc123", tool: "GMAIL_SEND_EMAIL", arguments: { to: "...", subject: "..." } }) Defensive patterns
Strategy: validation
Validate before calling
const tool = String(args?.tool ?? "").trim();
if (!tool) throw new Error("pick a tool name from sp_mcp_list_tools output"); Type guard
const hasTool = (a) => typeof a?.tool === "string" && a.tool.trim().length > 0;
Try / catch
try { await mcpCallTool(args) } catch (e) { if (e.message === "tool is required") { await sp_mcp_list_tools({ server_id: args.server_id }); /* pick tool, retry */ } else throw e } Prevention
- Copy tool names verbatim from sp_mcp_list_tools
- Trim tool names
- Pass per-tool parameters inside `arguments`
When it happens
Trigger: Calling with tool omitted, empty string, or whitespace-only; passing a description instead of the tool's callable name.
Common situations: Agents inventing tool names instead of reading sp_mcp_list_tools output; trailing-whitespace strings from copy/paste; templating bugs leaving the variable empty.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- server_id is required
- query is required
- connectionId is required
- OAuth is only supported for HTTP MCP servers
- stdio MCP server requires a non-empty command
AI-assisted analysis of screenpipe/screenpipe@4ebf712990 (2026-09-01).
Data as JSON: /api/errors/f506e185ccd4fb1f.
Report an issue: GitHub.