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

  1. Run sp_mcp_list_tools for the server_id and copy the exact tool name.
  2. Trim the tool string before calling.
  3. 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

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


AI-assisted analysis of screenpipe/screenpipe@4ebf712990 (2026-09-01). Data as JSON: /api/errors/f506e185ccd4fb1f. Report an issue: GitHub.