Skip to content
Files SDK
Esc
↑↓navigate↵open⌘Jpreview
On this page

Claude Agent SDK

Expose a configured Files instance to the Claude Agent SDK as an in-process MCP server with allowedTools and canUseTool wired up.

The files-sdk/claude subpath exposes a configured Files instance to the Claude Agent SDK (@anthropic-ai/claude-agent-sdk, the renamed Claude Code SDK). The Agent SDK consumes tools as an in-process MCP server plus an allowedTools allow-list and a canUseTool approval callback, so createClaudeFileTools returns a bundle of all three - pass them straight into query().

@anthropic-ai/claude-agent-sdk and zod are optional peer dependencies - only install them if you’re consuming this subpath.

Installation

npm install @anthropic-ai/claude-agent-sdk zod
pnpm add @anthropic-ai/claude-agent-sdk zod
yarn add @anthropic-ai/claude-agent-sdk zod
bun add @anthropic-ai/claude-agent-sdk zod
nub add @anthropic-ai/claude-agent-sdk zod
aube add @anthropic-ai/claude-agent-sdk zod

Quick start

createClaudeFileTools returns { mcpServers, allowedTools, canUseTool, needsApproval, server, serverName }. The first three slot directly into query()’s options; the rest are escape hatches for callers that want to compose with existing MCP servers or wire their own approval UX.

allowedTools lists only the tools that run without approval. The Agent SDK runs everything in allowedTools without asking canUseTool, so approval-gated writes are left out and every call to one reaches canUseTool. The bundled canUseTool covers only this bundle’s MCP server: it denies approval-gated writes, and it denies every other tool too (Bash, Write, other MCP servers). Use it as-is when file tools are the only ones the agent should run unprompted; otherwise compose your own.

import { query } from "@anthropic-ai/claude-agent-sdk";
import { Files } from "files-sdk";
import { s3 } from "files-sdk/s3";
import { createClaudeFileTools } from "files-sdk/claude";

const files = new Files({ adapter: s3({ bucket: "uploads" }) });
const tools = createClaudeFileTools({ files });

for await (const message of query({
  prompt: "Find every CSV under reports/ and summarize the latest one.",
  options: {
    mcpServers: tools.mcpServers,
    allowedTools: tools.allowedTools,
    canUseTool: tools.canUseTool,
  },
})) {
  // handle messages
}

Approval control

For tools on its own MCP server, the bundled canUseTool denies any tool whose needsApproval resolves to true with a "requires approval" message, and allows the rest. Tools that don’t need approval are also listed in allowedTools, so the SDK runs them without asking. requireApproval accepts a boolean for the all-or-nothing case, or an object keyed by write tool name for fine-grained control.

// All writes require approval (default) - denied by the bundled canUseTool.
createClaudeFileTools({ files });

// Disable the approval gate entirely - every file tool lands in allowedTools.
createClaudeFileTools({ files, requireApproval: false });

// Granular: only destructive operations need approval.
createClaudeFileTools({
  files,
  requireApproval: {
    deleteFile: true,
    signUploadUrl: true,
    uploadFile: false,
    copyFile: false,
  },
});

For real human-in-the-loop UX, or to authorize tools beyond this bundle, compose your own canUseTool. canUseTool is the permission callback for the whole session, so handle file tools with tools.needsApproval() (it accepts both bare names like "uploadFile" and the MCP-prefixed form the SDK passes in) and apply your own policy to everything else.

import { query } from "@anthropic-ai/claude-agent-sdk";
import type { CanUseTool } from "@anthropic-ai/claude-agent-sdk";

const tools = createClaudeFileTools({ files });
const filesPrefix = `mcp__${tools.serverName}__`;

const canUseTool: CanUseTool = async (name, input) => {
  if (!name.startsWith(filesPrefix)) {
    // Not a files-sdk tool: apply your own policy here. Deny by default.
    return { behavior: "deny", message: `${name} is not allowed.` };
  }
  if (tools.needsApproval(name)) {
    const approved = await askUser(name, input);
    return approved
      ? { behavior: "allow", updatedInput: input }
      : { behavior: "deny", message: "User rejected the call." };
  }
  return { behavior: "allow", updatedInput: input };
};

for await (const message of query({
  prompt: "Archive last quarter's reports.",
  options: {
    mcpServers: tools.mcpServers,
    // Gated writes aren't listed, so the SDK asks canUseTool about each one.
    allowedTools: tools.allowedTools,
    canUseTool,
  },
})) {
  // handle messages
}

Read-only mode

Pass readOnly: true to drop every write tool from the bundled MCP server. The model cannot mutate the bucket regardless of how requireApproval is configured.

// Strip every write tool. The model can browse but cannot mutate
// the bucket regardless of approval configuration.
createClaudeFileTools({ files, readOnly: true });
// allowedTools → ["mcp__files__downloadFile", "mcp__files__getFileMetadata",
//                 "mcp__files__getFileUrl", "mcp__files__listFiles"]

Server name

Claude addresses each MCP tool as mcp__<server-name>__<tool-name>. The default server name is "files"; override it via serverName when you need to namespace alongside another MCP server or just prefer a different label in transcripts.

// Override the MCP server name - affects the mcp__<server>__<tool>
// prefix the model sees, and the mcpServers map key.
const tools = createClaudeFileTools({ files, serverName: "storage" });
// tools.allowedTools → ["mcp__storage__downloadFile", ...]
// tools.mcpServers   → { storage: <McpSdkServerConfigWithInstance> }

Cherry-picking tools

Each tool factory is exported individually as a SdkMcpToolDefinition - bundle them into your own createSdkMcpServer call when you want full control over the MCP server shape or want to mix files-sdk tools with your own.

import { createSdkMcpServer } from "@anthropic-ai/claude-agent-sdk";
import { Files } from "files-sdk";
import {
  claudeDownloadFile,
  claudeListFiles,
  claudeUploadFile,
} from "files-sdk/claude";

const files = new Files({ adapter });

// Compose your own MCP server with just the tools you want.
const server = createSdkMcpServer({
  name: "files",
  version: "1.0.0",
  tools: [
    claudeListFiles(files),
    claudeDownloadFile(files),
    claudeUploadFile(files),
  ],
});

Was this page helpful?