200| :- | :- | :- | :- |200| :- | :- | :- | :- |
201| `title` | `string` | `undefined` | Human-readable title for the tool |201| `title` | `string` | `undefined` | Human-readable title for the tool |
202| `readOnlyHint` | `boolean` | `false` | If `true`, the tool does not modify its environment |202| `readOnlyHint` | `boolean` | `false` | If `true`, the tool does not modify its environment |
203| `destructiveHint` | `boolean` | `true` | If `true`, the tool may perform destructive updates (only meaningful when `readOnlyHint` is `false`) |203| `destructiveHint` | `boolean` | `true` | If `true`, the tool may perform destructive updates. Set `destructiveHint: true` explicitly on any tool you mark [`always_ask`](#mcpservertoolpolicy), or the auto mode classifier can approve that tool's calls in place of your `canUseTool` callback. Leaving `destructiveHint` unset isn't enough, because Claude Code treats an unset `destructiveHint` as `false` when it handles `always_ask` calls, although the MCP specification's default is `true` |
204| `idempotentHint` | `boolean` | `false` | If `true`, repeated calls with the same arguments have no additional effect (only meaningful when `readOnlyHint` is `false`) |204| `idempotentHint` | `boolean` | `false` | If `true`, repeated calls with the same arguments have no additional effect (only meaningful when `readOnlyHint` is `false`) |
205| `openWorldHint` | `boolean` | `true` | If `true`, the tool interacts with external entities (for example, web search). If `false`, the tool's domain is closed (for example, a memory tool) |205| `openWorldHint` | `boolean` | `true` | If `true`, the tool interacts with external entities (for example, web search). If `false`, the tool's domain is closed (for example, a memory tool) |
206 206
630 ): Promise<SDKControlReadFileResponse | null>;630 ): Promise<SDKControlReadFileResponse | null>;
631 reloadPlugins(options?: {631 reloadPlugins(options?: {
632 holdOnCacheImpact?: boolean;632 holdOnCacheImpact?: boolean;
633 addPlugins?: SdkPluginConfig[];
633 }): Promise<SDKControlReloadPluginsResponse>;634 }): Promise<SDKControlReloadPluginsResponse>;
634 reloadSkills(): Promise<SDKControlReloadSkillsResponse>;635 reloadSkills(): Promise<SDKControlReloadSkillsResponse>;
635 reloadOutputStyles(): Promise<SDKControlReloadOutputStylesResponse>;636 reloadOutputStyles(): Promise<SDKControlReloadOutputStylesResponse>;
669| `mcpServerStatus()` | Returns the status of connected MCP servers as [`McpServerStatus`](#mcpserverstatus)`[]` |670| `mcpServerStatus()` | Returns the status of connected MCP servers as [`McpServerStatus`](#mcpserverstatus)`[]` |
670| `getContextUsage(opts?)` | Returns an [`SDKControlGetContextUsageResponse`](#sdkcontrolgetcontextusageresponse) breaking down the session's context window usage by category, skill, and tool. With the default `detail`, it includes the data `/context` shows in an interactive session, computed with token-counting API requests that don't appear in the message stream; see [how these requests are handled](#sdkcontrolgetcontextusageresponse). The [`detail` option](#sdkcontrolgetcontextusageresponse) requires Agent SDK v0.3.257 or later |671| `getContextUsage(opts?)` | Returns an [`SDKControlGetContextUsageResponse`](#sdkcontrolgetcontextusageresponse) breaking down the session's context window usage by category, skill, and tool. With the default `detail`, it includes the data `/context` shows in an interactive session, computed with token-counting API requests that don't appear in the message stream; see [how these requests are handled](#sdkcontrolgetcontextusageresponse). The [`detail` option](#sdkcontrolgetcontextusageresponse) requires Agent SDK v0.3.257 or later |
671| `readFile(path, options?)` | Reads a file from the session's filesystem. Claude Code resolves the path against `cwd`; [What `readFile()` can read](#what-readfile-can-read) lists the files it serves. Pass `{ maxBytes }` to change the read cap (default 1 MB, ceiling 10 MB) and `{ encoding: 'base64' }` for binary files such as images. Resolves with an [`SDKControlReadFileResponse`](#sdkcontrolreadfileresponse), or `null` on permission denial, a missing file, or a transport error. Requires TypeScript SDK v0.2.121 or later |672| `readFile(path, options?)` | Reads a file from the session's filesystem. Claude Code resolves the path against `cwd`; [What `readFile()` can read](#what-readfile-can-read) lists the files it serves. Pass `{ maxBytes }` to change the read cap (default 1 MB, ceiling 10 MB) and `{ encoding: 'base64' }` for binary files such as images. Resolves with an [`SDKControlReadFileResponse`](#sdkcontrolreadfileresponse), or `null` on permission denial, a missing file, or a transport error. Requires TypeScript SDK v0.2.121 or later |
672| `reloadPlugins(options?)` | Reloads plugins from disk, so plugins you install or edit mid-session reach the running session. Resolves with an [`SDKControlReloadPluginsResponse`](#sdkcontrolreloadpluginsresponse) listing the session's commands, subagents, plugins, and MCP server status. Requires Agent SDK v0.2.85 or later. The [`holdOnCacheImpact` option](#sdkcontrolreloadpluginsresponse) requires Agent SDK v0.3.268 or later |673| `reloadPlugins(options?)` | Reloads plugins from disk, so plugins you install or edit mid-session reach the running session. Resolves with an [`SDKControlReloadPluginsResponse`](#sdkcontrolreloadpluginsresponse) listing the session's commands, subagents, plugins, and MCP server status. Requires Agent SDK v0.2.85 or later. The [`holdOnCacheImpact` option](#sdkcontrolreloadpluginsresponse) requires Agent SDK v0.3.268 or later. The [`addPlugins` option](#load-more-plugin-folders-with-addplugins) requires Agent SDK v0.3.301 or later |
673| `reloadSkills()` | Reloads skills from disk, so skills you add or edit mid-session become available to the running session. Resolves with an [`SDKControlReloadSkillsResponse`](#sdkcontrolreloadskillsresponse) listing the skills available after the reload. Requires Agent SDK v0.3.163 or later |674| `reloadSkills()` | Reloads skills from disk, so skills you add or edit mid-session become available to the running session. Resolves with an [`SDKControlReloadSkillsResponse`](#sdkcontrolreloadskillsresponse) listing the skills available after the reload. Requires Agent SDK v0.3.163 or later |
674| `reloadOutputStyles()` | Re-reads [output styles](https://code.claude.com/docs/en/output-styles.md) from disk, so a style file you add or edit mid-session becomes available to the running session. Resolves with an [`SDKControlReloadOutputStylesResponse`](#sdkcontrolreloadoutputstylesresponse) listing the style names available after the reload. Requires Agent SDK v0.3.261 or later |675| `reloadOutputStyles()` | Re-reads [output styles](https://code.claude.com/docs/en/output-styles.md) from disk, so a style file you add or edit mid-session becomes available to the running session. Resolves with an [`SDKControlReloadOutputStylesResponse`](#sdkcontrolreloadoutputstylesresponse) listing the style names available after the reload. Requires Agent SDK v0.3.261 or later |
675| `seedReadState(path, mtime)` | Marks a file as already read so a later Edit doesn't fail with `File has not been read yet`. See [`seedReadState()`](#seedreadstate). Requires TypeScript SDK v0.2.83 or later |676| `seedReadState(path, mtime)` | Marks a file as already read so a later Edit doesn't fail with `File has not been read yet`. See [`seedReadState()`](#seedreadstate). Requires TypeScript SDK v0.2.83 or later |
1135 1136
1136`cache_impact` is present only alongside `held: true`. `mcp_servers_added` and `mcp_servers_removed` name the plugin MCP servers the reload would register or drop, as scoped `plugin:<plugin>:<server>` names. The names are plugin-authored, so validate them before showing them. `lsp_tool_change` says whether applying would add or remove the LSP tool, or `null` when it would do neither. The `may-` forms mean the check couldn't fully see the pending plugin set.1137`cache_impact` is present only alongside `held: true`. `mcp_servers_added` and `mcp_servers_removed` name the plugin MCP servers the reload would register or drop, as scoped `plugin:<plugin>:<server>` names. The names are plugin-authored, so validate them before showing them. `lsp_tool_change` says whether applying would add or remove the LSP tool, or `null` when it would do neither. The `may-` forms mean the check couldn't fully see the pending plugin set.
1137 1138
1139#### Load more plugin folders with `addPlugins`
1140
1141To load plugin folders that weren't in the [`plugins`](#options) option at startup, pass them to `reloadPlugins()` as `addPlugins`, a list of [`SdkPluginConfig`](#sdkpluginconfig) entries whose `path` is absolute. Claude Code loads the new folders and reloads the session's existing plugins in one pass. Each added plugin's MCP servers connect too, unless you set [`skipMcpDiscovery`](#sdkpluginconfig) on that folder's entry. Requires Agent SDK v0.3.301 or later and Claude Code v2.1.301 or later.
1142
1143This example adds one folder to a running query `q` and prints the install path of every plugin the session has loaded when the call returns:
1144
1145```typescript theme={null}
1146const result = await q.reloadPlugins({
1147 addPlugins: [{ type: "local", path: "/opt/my-app/plugins/reports" }]
1148});
1149
1150console.log(result.plugins.map((plugin) => plugin.path));
1151```
1152
1153If the folder loaded, the printed list includes `/opt/my-app/plugins/reports`, and the plugin's commands and subagents appear in `result.commands` and `result.agents`.
1154
1155An added folder stays part of the session. When you call `reloadPlugins()` again, Claude Code reloads it with the other plugins, and you don't pass it in `addPlugins` again.
1156
1157##### When `reloadPlugins()` doesn't load the `addPlugins` folders
1158
1159If `reloadPlugins()` rejects, none of the `addPlugins` folders are added, so pass them in `addPlugins` again when you retry. When the rejection has one of the following causes, the session keeps the plugins it already had:
1160
1161* **A relative `path` or a malformed entry**: the error message says `add_plugins must be a list of { type: "local", path } entries with absolute paths`. Claude Code refuses the whole list over one bad entry, so pass every entry as `{ type: "local", path }` with an absolute `path`
1162* **An administrator has turned on [`disableSideloadFlags`](https://code.claude.com/docs/en/settings-reference#disablesideloadflags) in your managed settings**: the message says `reload_plugins add_plugins is disabled by managed settings (disableSideloadFlags)`. To load the folder, ask that administrator to remove the setting
1163* **The [sandbox](https://code.claude.com/docs/en/sandboxing.md) couldn't be rebuilt**: with [sandboxing](#sandboxsettings) on, Claude Code rebuilds the sandbox configuration so that sandboxed shell commands can't write to the folders you add. The message says `the sandbox could not be rebuilt to keep shell commands out of this folder`. Check that your [sandbox settings](#sandboxsettings) still form a valid configuration
1164
1165If you pass `holdOnCacheImpact` and the call resolves with [`held: true`](#sdkcontrolreloadpluginsresponse), the `addPlugins` folders aren't added. To add them anyway, call `reloadPlugins()` again with the same `addPlugins` list and without `holdOnCacheImpact`.
1166
1167When the call resolves without `held: true` and a folder is still missing from `result.plugins`, start by checking for these causes:
1168
1169* **The folder doesn't exist or its plugin failed to load**: `result.error_count` is `1` or higher. The folder stays part of the session even so. After you fix the folder, call `reloadPlugins()` again to load it, this time without listing it in `addPlugins`
1170* **The Claude Code executable is older than v2.1.301**: an executable older than v2.1.301 ignores `addPlugins` and reloads only the plugins the session already had. Check `claude_code_version` on the [init message](#sdksystemmessage), and run an executable at v2.1.301 or later
1171
1138### `SDKControlReloadSkillsResponse`1172### `SDKControlReloadSkillsResponse`
1139 1173
1140Return type of [`reloadSkills()`](#query-object).1174Return type of [`reloadSkills()`](#query-object).
1430 1464
1431#### `McpSdkServerConfigWithInstance`1465#### `McpSdkServerConfigWithInstance`
1432 1466
1467The configuration for an in-process MCP server, one that [`createSdkMcpServer()`](#createsdkmcpserver) creates and that runs inside your application's process. It is the object `createSdkMcpServer()` returns, plus an optional `tools` list of [`McpServerToolPolicy`](#mcpservertoolpolicy) entries that you add yourself. To require approval for calls to one of the server's tools, or to deny them, add an entry that names the tool.
1468
1433```typescript theme={null}1469```typescript theme={null}
1434type McpSdkServerConfigWithInstance = {1470type McpSdkServerConfigWithInstance = {
1435 type: "sdk";1471 type: "sdk";
1436 name: string;1472 name: string;
1437 timeout?: number;1473 timeout?: number;
1474 tools?: McpServerToolPolicy[];
1438 instance: McpServer;1475 instance: McpServer;
1439};1476};
1440```1477```
1441 1478
1479To set a policy, spread the object `createSdkMcpServer()` returns into a new object in `mcpServers` and add the `tools` list to that new object. The `tools` option of `createSdkMcpServer()` itself is a different list, which holds the tool definitions and doesn't accept policy entries. The policy list requires Agent SDK v0.3.301 or later, and [`McpServerToolPolicy`](#mcpservertoolpolicy) describes what each `permission_policy` value does.
1480
1481This example pre-approves every tool on the `records` server with an `allowedTools` wildcard, then marks `delete_record` as `always_ask` so that calls to it go to `canUseTool` anyway. With the `destructiveHint: true` annotation, the call still reaches the callback if the session runs in `auto` mode, where the auto mode [classifier](https://code.claude.com/docs/en/permission-modes.md#eliminate-prompts-with-auto-mode) could otherwise approve it.
1482
1483```typescript theme={null}
1484import { query, tool, createSdkMcpServer } from "@anthropic-ai/claude-agent-sdk";
1485import { z } from "zod";
1486
1487const deleteRecord = tool(
1488 "delete_record",
1489 "Delete a customer record by ID",
1490 { id: z.string() },
1491 async ({ id }) => ({ content: [{ type: "text", text: `Deleted record ${id}` }] }),
1492 { annotations: { destructiveHint: true } }
1493);
1494
1495const records = createSdkMcpServer({ name: "records", tools: [deleteRecord] });
1496
1497for await (const message of query({
1498 prompt: "Delete customer record 42",
1499 options: {
1500 mcpServers: {
1501 // Spread the returned config and add the policy list beside it
1502 records: {
1503 ...records,
1504 tools: [{ name: "delete_record", permission_policy: "always_ask" as const }]
1505 }
1506 },
1507 allowedTools: ["mcp__records__*"],
1508 canUseTool: async (toolName, input) => {
1509 console.log(`Approval requested for ${toolName}`);
1510 return { behavior: "allow", updatedInput: input };
1511 }
1512 }
1513})) {
1514 if (message.type === "result" && message.subtype === "success") {
1515 console.log(message.result);
1516 }
1517}
1518```
1519
1520When Claude calls the tool, the script prints `Approval requested for mcp__records__delete_record` before the `delete_record` tool runs, although the `allowedTools` entry would otherwise have approved the call.
1521
1522To change or lift a tool's policy while the session runs, pass the server's config with a new `tools` value to [`setMcpServers()`](#mcpsetserversresult). The `tools` value you pass takes effect from Claude's next call to that server's tools:
1523
1524* **A list with entries**: the entries replace the current policies
1525* **An empty list**: every policy on the server is cleared
1526* **No `tools` key**: the current policies stay
1527
1528Include in that call your other in-process servers and any server an earlier `setMcpServers()` call added, or the call disconnects them.
1529
1530#### `McpServerToolPolicy`
1531
1532One entry in an [`McpSdkServerConfigWithInstance`](#mcpsdkserverconfigwithinstance)'s `tools` list, naming one of the server's tools and setting the permission policy for calls to that tool. The list requires Agent SDK v0.3.301 or later and Claude Code v2.1.301 or later. An older Claude Code executable, such as an executable you point `pathToClaudeCodeExecutable` at, ignores the list. Then `always_ask` and `always_deny` aren't enforced, and each call goes through the [permission flow](https://code.claude.com/docs/en/agent-sdk/permissions.md#how-permissions-are-evaluated).
1533
1534```typescript theme={null}
1535type McpServerToolPolicy = {
1536 name: string;
1537 permission_policy?: "always_allow" | "always_ask" | "always_deny";
1538 org_max_permission?: "allow" | "ask" | "blocked";
1539};
1540```
1541
1542| Field | Type | Description |
1543| :- | :- | :- |
1544| `name` | `string` | The tool's bare name as passed to [`tool()`](#tool), without the `mcp__<server>__` prefix |
1545| `permission_policy` | `'always_allow' \| 'always_ask' \| 'always_deny'` | The approval policy for the tool's calls, [`always_ask` or `always_deny`](#permission-policy-values). `always_allow` is ignored on an in-process server: to pre-approve a tool, list it in [`allowedTools`](#options) instead |
1546| `org_max_permission` | `'allow' \| 'ask' \| 'blocked'` | A per-tool ceiling that an organization admin sets. Ignored on an in-process server, so leave it unset |
1547
1548##### `permission_policy` values
1549
1550Choose `always_ask` to approve each call yourself, or `always_deny` to block the tool outright:
1551
1552* **`always_ask`**: each call to the tool [needs approval](https://code.claude.com/docs/en/agent-sdk/permissions.md#how-permissions-are-evaluated), even if an `allowedTools` entry or allow rule covers it. The call goes to your `canUseTool` callback or [`permissionPromptToolName`](#options) tool, unless it's settled first. A [mod](https://code.claude.com/docs/en/plugins/mods/overview.md) in a plugin you load [can approve it first](https://code.claude.com/docs/en/permissions.md#precedence-among-rules-hooks-and-mods). Otherwise, in `dontAsk` mode it's denied, and in [`auto`, `plan`, and `bypassPermissions` mode](#permission-modes-that-can-approve-an-always_ask-call) it can be approved before it reaches your callback
1553* **`always_deny`**: a call to the tool [is denied](https://code.claude.com/docs/en/agent-sdk/permissions.md#how-permissions-are-evaluated) in every permission mode, including `bypassPermissions`, but a mod in a plugin you load [can still approve it](https://code.claude.com/docs/en/permissions.md#precedence-among-rules-hooks-and-mods)
1554
1555If you pass neither `canUseTool` nor `permissionPromptToolName`, or set [`permissionPrompts`](#options) to `'none'`, an `always_ask` call that isn't settled first is denied unless a [`PermissionRequest` hook](https://code.claude.com/docs/en/hooks#permissionrequest) allows it.
1556
1557##### Permission modes that can approve an `always_ask` call
1558
1559In `auto`, `plan`, and `bypassPermissions` mode, a call to a tool marked [`always_ask`](#permission-policy-values) can be approved before it reaches your `canUseTool` callback. Find your session's mode in this list to see when that approval happens and what to set so the call reaches your callback anyway:
1560
1561* **`auto`**: the auto mode [classifier](https://code.claude.com/docs/en/permission-modes.md#eliminate-prompts-with-auto-mode) reviews the call and can allow it. To make every call reach your callback in `auto` mode, set `destructiveHint: true` in the tool's [annotations](#toolannotations)
1562* **`plan`**: while [auto mode is available](https://code.claude.com/docs/en/permission-modes.md#eliminate-prompts-with-auto-mode) to the session, calls to an `always_ask` tool annotated `readOnlyHint: true` go to the auto mode classifier, which can allow them. Calls to other `always_ask` tools reach your callback. To make a read-only tool's calls reach your callback too, add `destructiveHint: true` to that tool's annotations alongside `readOnlyHint: true`. Alternatively, set [`useAutoModeDuringPlan`](https://code.claude.com/docs/en/settings-reference#useautomodeduringplan) to `false`, which turns the classifier off during planning
1563* **`bypassPermissions`**: when the [`CLAUDE_CODE_REMOTE`](https://code.claude.com/docs/en/env-vars#variables) environment variable is `true`, as it is in a [cloud session](https://code.claude.com/docs/en/claude-code-on-the-web.md), the call is approved without your callback, whatever the tool's annotations. Anywhere else the call reaches your callback. To make it reach your callback in a cloud session too, run the session in `default` or `acceptEdits` mode instead
1564
1565Set `destructiveHint` to `true` explicitly in `auto` and `plan` mode. For `always_ask` calls, Claude Code reads an unset `destructiveHint` as `false`, although the default listed under [`ToolAnnotations`](#toolannotations) is `true`.
1566
1442#### `McpClaudeAIProxyServerConfig`1567#### `McpClaudeAIProxyServerConfig`
1443 1568
1444```typescript theme={null}1569```typescript theme={null}
1464| Field | Type | Description |1589| Field | Type | Description |
1465| :- | :- | :- |1590| :- | :- | :- |
1466| `type` | `'local'` | Must be `'local'` (only local plugins currently supported) |1591| `type` | `'local'` | Must be `'local'` (only local plugins currently supported) |
1467| `path` | `string` | Absolute or relative path to the plugin directory |1592| `path` | `string` | Path to the plugin directory. A relative path resolves against the [`cwd`](#options) option when the session starts. The path must be absolute when you load the plugin mid-session with [`addPlugins`](#load-more-plugin-folders-with-addplugins) |
1468| `skipMcpDiscovery` | `boolean` | When `true`, the SDK loads skills, hooks, agents, and commands from this plugin but does not read its `.mcp.json` or manifest `mcpServers`. Set this when your application owns the plugin's MCP connections. |1593| `skipMcpDiscovery` | `boolean` | When `true`, the SDK loads skills, hooks, agents, and commands from this plugin but does not read its `.mcp.json` or manifest `mcpServers`. Set this when your application owns the plugin's MCP connections. |
1469 1594
1470**Example:**1595**Example:**
5076};5201};
5077```5202```
5078 5203
5079`source` says where the server's definition came from, with the same values and trust rule as [`McpServerProvenance`](#mcpserverprovenance)'s `source`. The field requires Agent SDK v0.3.274 or later and is absent on earlier versions.5204Use `source` to decide how far to trust a server, and the `_meta` on each `tools` entry to find a UI resource the server attached to that tool:
5205
5206* **`source`**: where the server's definition came from, with the same values as `source` on [`McpServerProvenance`](#mcpserverprovenance). Base trust decisions on `source` rather than on `name`, because only your own in-process server reports `sdk`, whatever name any other server is registered under. If you don't recognize a `source` value, treat that server as you treat any server whose `source` isn't `sdk`. Requires Agent SDK v0.3.274 or later
5207* **`_meta`**: the `ui` object and the `ui/resourceUri` string from the `_meta` the server declared for the tool. Claude Code withholds every other `_meta` key. `ui/resourceUri` is an older top-level spelling of `ui.resourceUri`. When the server attaches an [MCP Apps UI resource](https://code.claude.com/docs/en/mcp.md#reference-mcp-resources) to the tool, `ui.resourceUri` or `ui/resourceUri` holds the resource's `ui://` URI. Fetch that URI with [`readMcpResource()`](#query-object) and render the resource in your application. Requires Agent SDK v0.3.280 or later
5208
5209Claude Code sends `_meta` only when the [`capabilities`](#sdksystemmessage) array of the `system` message with subtype `init` lists `mcp_tool_ui_meta_v1`. You don't turn `mcp_tool_ui_meta_v1` on yourself.
5210
5211#### When a tool's `_meta.ui` holds only `visibility`
5212
5213If your server declares `ui.resourceUri` for a tool but the `_meta.ui` your application receives holds only `visibility`, the `ui` object the server sent failed one of Claude Code's checks. Claude Code checks `ui` and `ui/resourceUri` separately, so one key can reach your application when the other fails. Compare the `_meta` in your server's `tools/list` response against the checks for each key:
5214
5215* **`ui`**: reaches your application unchanged, including any members other than `resourceUri` and `visibility`, if all three checks pass:
5216
5217 * `resourceUri` is absent, or is a string that starts with `ui://`
5218 * `visibility` is absent, or lists only `"model"` and `"app"`
5219 * The whole object is at most 4,096 characters when serialized as JSON
5220
5221 If any of the checks fails, your application receives at most a `ui` whose only member is a `visibility` array with the `"model"` and `"app"` entries the server listed.
5222* **`ui/resourceUri`**: reaches your application if it is a string that starts with `ui://` and is at most 4,096 characters. Otherwise Claude Code drops it
5080 5223
5081`_meta` on a `tools` entry carries the MCP Apps members of that tool's `_meta`, so your application can find the `ui://` resource to render with [`readMcpResource()`](#query-object). Claude Code passes through the `ui` object and the deprecated flat `ui/resourceUri` string, and withholds every other key. Inside `ui`, `resourceUri` is a `ui://` string and `visibility` an array of `"model"` and `"app"` when the server sets them, and any other member passes through unchanged. Claude Code drops either key when the value is malformed, and omits `_meta` from a tool that declares neither. The field is present only when the init message's [`capabilities`](#sdksystemmessage) include `mcp_tool_ui_meta_v1`, and requires TypeScript Agent SDK v0.3.280 or later.5224When Claude Code is left with no `ui` member and no `ui/resourceUri` string to send, the `tools` entry has no `_meta` at all.
5082 5225
5083### `McpServerStatusConfig`5226### `McpServerStatusConfig`
5084 5227
5313When you call `setMcpServers()`, Claude Code applies these rules:5456When you call `setMcpServers()`, Claude Code applies these rules:
5314 5457
5315* **Servers the call doesn't name**: outside a [cloud session](https://code.claude.com/docs/en/claude-code-on-the-web.md), Claude Code disconnects the servers an earlier `setMcpServers()` call added and the in-process SDK servers, and lists them in `removed`. Other servers keep running and aren't listed in `removed`, among them the stdio, HTTP, and SSE servers from the [`mcpServers`](#options) option, servers from settings files, and plugin-provided servers.5458* **Servers the call doesn't name**: outside a [cloud session](https://code.claude.com/docs/en/claude-code-on-the-web.md), Claude Code disconnects the servers an earlier `setMcpServers()` call added and the in-process SDK servers, and lists them in `removed`. Other servers keep running and aren't listed in `removed`, among them the stdio, HTTP, and SSE servers from the [`mcpServers`](#options) option, servers from settings files, and plugin-provided servers.
5316* **Servers the call names**: Claude Code replaces a stdio, HTTP, or SSE server that an earlier `setMcpServers()` call added only when its config differs from the one you passed. An in-process SDK server already registered under that name stays as it is, so to swap one, leave it out of one call and add it in the next.5459* **Stdio, HTTP, and SSE servers that an earlier `setMcpServers()` call added**: outside a cloud session, a server you name again with an identical config keeps its connection and tools. It appears in neither `added` nor `removed`. If you pass a changed config, Claude Code reconnects the server using that config and lists it in `added`, not in `removed`.
5460* **Stdio, HTTP, and SSE servers the call names that no earlier call added**: outside a cloud session, Claude Code adds the server and lists it in `added`, or in `errors` if it refuses the server.
5461* **In-process SDK servers the call names**: a server already registered through `mcpServers` or an earlier call keeps its running instance and timeout. If you pass a [`tools` policy list](#mcpsdkserverconfigwithinstance) for it, even an empty one, you replace its policies; otherwise they stay. To run a new instance outside a cloud session, omit the server from one call and name it in the next.
5317* **Built-in servers the CLI started at startup**: if the call names one, Claude Code drops that entry and reports it in `errors`.5462* **Built-in servers the CLI started at startup**: if the call names one, Claude Code drops that entry and reports it in `errors`.
5318* **Stdio, HTTP, or SSE servers that share a name with one from an MCP installation scope such as `.mcp.json`**: under that name the session uses your server's tools rather than the [installation-scope server's](https://code.claude.com/docs/en/mcp.md#mcp-installation-scopes). Before Claude Code v2.1.305, Claude Code could disconnect your server and connect the installation-scope server when your app [reloaded plugins](#query-object).5463* **Stdio, HTTP, or SSE servers that share a name with one from an MCP installation scope such as `.mcp.json`**: under that name the session uses your server's tools rather than the [installation-scope server's](https://code.claude.com/docs/en/mcp.md#mcp-installation-scopes). Before Claude Code v2.1.305, Claude Code could disconnect your server and connect the installation-scope server when your app [reloaded plugins](#query-object).
5319 5464
5800 5945
5801The SDK's published typings declare `SDKConversationResetMessage` in Claude Code v2.1.203 and later. Before v2.1.203, `SDKMessage` referenced the type without declaring it, so narrowing on `type === "conversation_reset"` failed to typecheck when `skipLibCheck` was disabled.5946The SDK's published typings declare `SDKConversationResetMessage` in Claude Code v2.1.203 and later. Before v2.1.203, `SDKMessage` referenced the type without declaring it, so narrowing on `type === "conversation_reset"` failed to typecheck when `skipLibCheck` was disabled.
5802 5947
5948### `BUILTIN_TOOL_NAMES` and `LEGACY_TOOL_NAME_ALIASES`
5949
5950Use these two constants to check tool names that your application's users enter. Both spell each name the way you write it in permission rules, hook matchers, and the `tools` and `disallowedTools` options. Import them from `@anthropic-ai/claude-agent-sdk` or from `@anthropic-ai/claude-agent-sdk/core`. They require Agent SDK v0.3.301 or later and are alpha.
5951
5952The SDK's type declarations give `BUILTIN_TOOL_NAMES` a readonly tuple type and `LEGACY_TOOL_NAME_ALIASES` a string-to-string record type:
5953
5954```typescript theme={null}
5955const BUILTIN_TOOL_NAMES: readonly ["Agent", /* ...more names... */ "Write"];
5956const LEGACY_TOOL_NAME_ALIASES: Readonly<Record<string, string>>;
5957```
5958
5959* **`BUILTIN_TOOL_NAMES`**: names of Claude Code's built-in tools in alphabetical order, such as `Agent`, `Bash`, and `Read`. MCP tool names aren't included. Because the type is a tuple of string literals, `(typeof BUILTIN_TOOL_NAMES)[number]` gives you a union type of the names
5960* **`LEGACY_TOOL_NAME_ALIASES`**: earlier tool names that permission rules, hook matchers, and the `tools` and `disallowedTools` options still accept. Each key is an earlier name and its value is the current one: for example, `Task` maps to `Agent`, and `KillShell` and `KillBash` map to `TaskStop`
5961
5962You can confirm a name with either of two tests: `BUILTIN_TOOL_NAMES` includes it, or `Object.hasOwn(LEGACY_TOOL_NAME_ALIASES, name)` returns `true`. A name that fails both can still be valid, because `BUILTIN_TOOL_NAMES` leaves out MCP tools and some built-in tools. If you build a deny list from `BUILTIN_TOOL_NAMES`, Claude can still use the tools the constant leaves out. To deny every tool, set [`disallowedTools: ["*"]`](https://code.claude.com/docs/en/agent-sdk/permissions#allow-and-deny-rules) instead.
5963
5964Finding a name in `BUILTIN_TOOL_NAMES` doesn't tell you the session has that tool: `TodoWrite` is listed even though it's [disabled by default](https://code.claude.com/docs/en/tools-reference.md). To see which tools a session has, read the `tools` array of its [`SDKSystemMessage`](#sdksystemmessage). That array includes MCP tools and lists the Agent tool as `Task`, so map each name through `LEGACY_TOOL_NAME_ALIASES` before comparing it with `BUILTIN_TOOL_NAMES`.
5965
5803### `AbortError`5966### `AbortError`
5804 5967
5805Custom error class for abort operations.5968Custom error class for abort operations.