Mastra MCP client: connect an agent to Sume's hosted MCP

Connect a Mastra agent to Sume's hosted MCP server with MCPClient: an API-key header in requestInit, a tool allow-list, and approval for paid calls.

5 min readSume
All posts

To connect a Mastra agent to Sume's tools, create an MCPClient with a sume server at new URL("https://mcp.sume.com/mcp"), put your Sume API key in requestInit.headers as Authorization: Bearer, set requireToolApproval so paid calls wait for a person, and give the agent only the tools it needs from await mcp.listTools().

The Mastra facts come from its MCP guide, MCPClient reference, and human-in-the-loop pages; the Sume facts come from OAuth and API keys, MCP tools and gates, and Jobs and results, all read on 2026-09-27. Sume has no Mastra package or plugin; MCPClient from @mastra/mcp is Mastra's own client. Sume's basics page says hosted MCP still works but is not part of the primary path today. For a REST tool instead, see Vercel AI SDK: generate video with a Sume API tool call.

How do I configure MCPClient for Sume?

Install @mastra/mcp@latest. A server defined by a url uses the Streamable HTTP transport, and requestInit is the fetch configuration for its requests. Sume takes the key as Authorization: Bearer or x-api-key; send one of the two, from an environment variable, as Mastra's docs advise for API keys:

import { Agent } from "@mastra/core/agent";
import { MCPClient } from "@mastra/mcp";

export const mcp = new MCPClient({
  id: "sume-mcp",
  servers: {
    sume: {
      url: new URL("https://mcp.sume.com/mcp"),
      requestInit: { headers: { Authorization: `Bearer ${process.env.SUME_API_KEY}` } },
      requireToolApproval: ({ toolName, args }) =>
        toolName === "generate_video" && args.dry_run !== true,
    },
  },
});

const keep = ["tools_schema", "balance_get", "generate_video", "jobs_wait", "jobs_result"];
const tools = Object.fromEntries(
  Object.entries(await mcp.listTools()).filter(([name]) => keep.some((t) => name === `sume_${t}`)),
);

export const producer = new Agent({
  id: "producer",
  name: "Video producer",
  instructions: "Preview generate_video with dry_run: true first. Wait with jobs_wait; never resubmit.",
  model: "openai/gpt-5-mini",
  tools,
});

Which tool names will the agent see?

listTools() returns the tools of every configured server, namespaced as serverName_toolName, so Sume's generate_video becomes sume_generate_video. An API-key session on Sume sees write and paid tools, so the example keeps five; the Sume MCP tools list sorts the rest by whether they read, write, or spend.

Tool groups from Sume's MCP tools and gates; naming from Mastra's MCPClient reference, read 2026-09-27.
Name in MastraSume groupApproval
sume_tools_schemaDiscoveryNo
sume_balance_getAccount and catalogNo
sume_generate_videoPaid; needs idempotency_keyYes, unless dry_run is true
sume_jobs_wait, sume_jobs_resultJobs, readNo
sume_jobs_cancelJobs, writeLeft out

How do paid Sume calls wait for approval?

On a server definition, requireToolApproval takes true or a function that receives the tool name, the arguments the model passed, the request context, and any annotations the server advertises. Mastra lists cost-heavy calls to third-party APIs, where you want to verify arguments first, as a reason for human-in-the-loop.

When a call needs approval, the stream emits a tool-call-approval chunk with toolCallId, toolName, and args. Continue with agent.approveToolCall({ runId }) or agent.declineToolCall({ runId }). With generate(), the result comes back with finishReason: 'suspended', and approveToolCallGenerate({ runId, toolCallId }) continues it.

  • Approval uses snapshots, so configure a storage provider on your Mastra instance or you'll see a "snapshot not found" error.
  • Decide on tool names, not annotations: Mastra says to treat annotations from servers you don't control as untrusted hints.
  • Sume's own gates still apply: dry_run=true previews admission and cost without submitting the job, and max_spend_usd caps a call only when you pass it. Estimate AI video cost before you run covers the preview.

Is MCPClient's timeout long enough for jobs_wait?

Yes, with a few seconds to spare. The client-level timeout defaults to 60000 milliseconds, and a server-level timeout overrides it. Sume's jobs_wait holds one call for at most 55 seconds, or 50 when timeout_seconds is omitted, so keep the timeout at or above the default.

  • On wait_slice_expired, call jobs_wait again with the same ids; never resubmit the paid create. A 524, 522, 523, or 525 on jobs_wait is a transport failure, not a job outcome.
  • By default (onToolError: 'throw'), an in-band tool error raises a MastraError carrying the server's error text, so the failure reaches the model.

Should I use listTools or listToolsets?

Use listTools() in the Agent constructor when one Sume key serves every request: its credentials are shared by all requests. When each of your users has their own Sume key, create a client per request, pass await client.listToolsets() to generate() or stream(), and call disconnect() when the response is done. listToolsets() names tools serverName.toolName.

Sources

Related posts

More in Integrations

All Integrations posts

Written by Sume