AI SDK MCP tools(): explicit Zod schemas for Sume's jobs_wait

Pass explicit Zod schemas to mcpClient.tools() so your app exposes only the Sume tools it needs, with typed job ids and a bounded wait_for.

5 min readSume
All posts

The AI SDK's MCP client can discover every tool a server offers, or you can name the ones you want. The AI SDK MCP tools page says schema discovery uses mcpClient.tools(), and that explicit Zod schemas pull only the named tools and give TypeScript types, read 2026-10-03. A tool with no arguments uses an empty object schema. For a Sume integration that only needs to wait on and read jobs, that is a smaller, safer surface than every create tool.

Schemas for the read-side tools

Sume's tools and gates page says jobs_wait takes job_ids (1 to 20) and wait_for of all or any. The schema below encodes those limits. Only the fields the docs name are included; if the server accepts more, the AI SDK page does not say how extra fields are handled, so check the tool's schema with tools_schema.

The transport shape comes from the AI SDK page: type: 'http', a url, and headers. It recommends HTTP for production.

import { createMCPClient } from "@ai-sdk/mcp";
import { z } from "zod";

const client = await createMCPClient({
  transport: {
    type: "http",
    url: "https://mcp.sume.com/mcp",
    headers: { Authorization: `Bearer ${process.env.SUME_API_KEY}` },
  },
});
try {
  const tools = await client.tools({
    schemas: {
      jobs_wait: {
        inputSchema: z.object({
          job_ids: z.array(z.string()).min(1).max(20),
          wait_for: z.enum(["all", "any"]).optional(),
        }),
      },
    },
  });
  console.log(Object.keys(tools));
} finally {
  await client.close();
}

Why restrict the tool list

Sume gates paid and write tools with idempotency_key, and under OAuth with the mcp:write scope, but a model that never sees the create tool cannot call it. Restrict first, gate second.

Discovery versus explicit schemas, read 2026-10-03.
ApproachTools exposedTrade-off
tools() with no schemasEverything the server listsIncludes paid create tools; the model may call them
tools({ schemas })Only the named toolsYou maintain the schemas; types are checked
Zero-argument toolEmpty z.object({})Needed for tools that take no input

Close the client

The page says to close the client with onEnd for streams or try/finally otherwise, which the snippet does. A leaked client keeps a connection open. For waits longer than a single hold, loop in your own code on wait_slice_expired using the same ids; never resubmit a paid create.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume