12 KiB
Managed Agents — Tools & Skills
Tools
Server tools vs client tools
| Type | Who runs it | How it works |
|---|---|---|
Prebuilt Claude Agent tools (agent_toolset_20260401) |
Anthropic, on the session's container | File ops, bash, web search, etc. Enable all at once or configure individually with enabled: true/false. |
MCP tools (mcp_toolset) |
Anthropic, on the session's container | Capabilities exposed by connected MCP servers. Grant access per-server via the toolset. |
| Custom tools | You — your application handles the call and returns results | Agent emits a agent.custom_tool_use event, session goes idle, you send back a user.custom_tool_result event. |
Recommendation: Enable all prebuilt tools via agent_toolset_20260401, then disable individually as needed.
Versioning: The toolset is a versioned, static resource. When underlying tools change, a new toolset version is created (hence _20260401) so you always know exactly what you're getting.
Agent Toolset
The agent_toolset_20260401 provides these built-in tools:
| Tool | Description |
|---|---|
bash |
Execute bash commands in a shell session |
read |
Read a file from the local filesystem, including text, images, PDFs, and Jupyter notebooks |
write |
Write a file to the local filesystem |
edit |
Perform string replacement in a file |
glob |
Fast file pattern matching using glob patterns |
grep |
Text search using regex patterns |
web_fetch |
Fetch content from a URL |
web_search |
Search the web for information |
Enable the full toolset:
{
"tools": [
{ "type": "agent_toolset_20260401" }
]
}
Per-Tool Configuration
Override defaults for individual tools. This example enables everything except bash:
{
"tools": [
{
"type": "agent_toolset_20260401",
"default_config": { "enabled": true },
"configs": [
{ "name": "bash", "enabled": false }
]
}
]
}
| Field | Required | Description |
|---|---|---|
type |
✅ | "agent_toolset_20260401" |
default_config |
❌ | Applied to all tools. { "enabled": bool, "permission_policy": {...} } |
configs |
❌ | Per-tool overrides: [{ "name": "...", "enabled": bool, "permission_policy": {...} }] |
Permission Policies
Control when server-executed tools (agent toolset + MCP) run automatically vs wait for approval. Does not apply to custom tools.
| Policy | Behavior |
|---|---|
always_allow |
Tool executes automatically (default) |
always_ask |
Session emits session.status_idle and pauses until you send a tool_confirmation event |
{
"type": "agent_toolset_20260401",
"default_config": {
"enabled": true,
"permission_policy": { "type": "always_allow" }
},
"configs": [
{ "name": "bash", "permission_policy": { "type": "always_ask" } }
]
}
Responding to always_ask: Send a user.tool_confirmation event with tool_use_id from the triggering agent_tool_use/mcp_tool_use event:
{ "type": "tool_confirmation", "tool_use_id": "sevt_abc123", "result": "allow" }
{ "type": "tool_confirmation", "tool_use_id": "sevt_def456", "result": "deny", "message": "Read .env.example instead" }
The optional message on a deny is delivered to the agent so it can adjust its approach.
To enable only specific tools, flip the default off and opt-in per tool:
{
"tools": [
{
"type": "agent_toolset_20260401",
"default_config": { "enabled": false },
"configs": [
{ "name": "bash", "enabled": true },
{ "name": "read", "enabled": true }
]
}
]
}
Custom Tools (Client-Side)
Custom tools are executed by your application, not Anthropic. The flow:
- Agent decides to use the tool → session emits a
agent.custom_tool_useevent with inputs - Session goes
idlewaiting for you - Your application executes the tool
- You send back a
user.custom_tool_resultevent with the output - Session resumes
running
No permission policy needed — you're the one executing.
{
"tools": [
{
"type": "custom",
"name": "get_weather",
"description": "Fetch current weather for a city.",
"input_schema": {
"type": "object",
"properties": {
"city": { "type": "string", "description": "City name" }
},
"required": ["city"]
}
}
]
}
MCP Servers
MCP (Model Context Protocol) servers expose standardized third-party capabilities (e.g. Asana, GitHub, Linear). Configuration is split across agent and vault:
- Agent creation declares which servers to connect to (
type,name,url— no auth). The agent'smcp_serversarray has no auth field. - Vault stores the OAuth credentials. Attach via
vault_idson session create.
This keeps secrets out of reusable agent definitions. Each vault credential is tied to one MCP server URL; Anthropic matches credentials to servers by URL.
Agent side — declare servers (no auth):
| Field | Required | Description |
|---|---|---|
type |
✅ | "url" |
name |
✅ | Unique name — referenced by mcp_toolset.mcp_server_name |
url |
✅ | The MCP server's endpoint URL (Streamable HTTP transport) |
{
"mcp_servers": [
{ "type": "url", "name": "linear", "url": "https://mcp.linear.app/mcp" }
],
"tools": [
{ "type": "mcp_toolset", "mcp_server_name": "linear" }
]
}
Session side — attach vault:
{
"agent": "agent_abc123",
"environment_id": "env_abc123",
"vault_ids": ["vlt_abc123"]
}
💡 Per-tool enablement (empirical):
mcp_toolsethas been observed acceptingdefault_config: {enabled: false}+configs: [{name, enabled: true}]for an allowlist pattern. The API ref shows only the minimal{type, mcp_server_name}form.
⚠️ MCP auth tokens ≠ REST API tokens. Hosted MCP servers (
mcp.notion.com,mcp.linear.app, etc.) typically require OAuth bearer tokens, not the service's native API keys. A Notionntn_integration token authenticates against Notion's REST API but will not work as a vault credential for the Notion MCP server. These are different auth systems.
Vaults — the MCP credential store
Vaults store OAuth credentials (access token + refresh token) that Anthropic auto-refreshes on your behalf via standard OAuth 2.0 refresh_token grant. This is the only way to authenticate MCP servers in the launch SDK.
Formerly known internally as TATs (Tool/Tenant Access Tokens).
Flow:
- Create a vault (
client.beta.vaults.create(...)) — one per tenant/user, or one shared, depending on your model - Add MCP credentials to it (
client.beta.vaults.credentials.create(...)) — each credential is tied to one MCP server URL - Reference the vault on session create via
vault_ids: ["vlt_..."] - Anthropic auto-refreshes tokens before they expire; the agent uses the current access token when calling MCP tools
Credential shape:
{
"display_name": "Notion (workspace-foo)",
"auth": {
"type": "mcp_oauth",
"mcp_server_url": "https://mcp.notion.com/mcp",
"access_token": "<current access token>",
"expires_at": "2026-04-02T14:00:00Z",
"refresh": {
"refresh_token": "<refresh token>",
"client_id": "<your OAuth client_id>",
"token_endpoint": "https://api.notion.com/v1/oauth/token",
"token_endpoint_auth": { "type": "none" }
}
}
}
The refresh block is what enables auto-refresh — token_endpoint is where Anthropic posts the refresh_token grant. token_endpoint_auth is a discriminated union:
type |
Shape | Use when |
|---|---|---|
"none" |
{type: "none"} |
Public OAuth client (no secret) |
"client_secret_basic" |
{type: "client_secret_basic", client_secret: "..."} |
Confidential client, secret via HTTP Basic auth |
"client_secret_post" |
{type: "client_secret_post", client_secret: "..."} |
Confidential client, secret in request body |
Omit refresh entirely if you only have an access token with no refresh capability — it'll work until it expires, then the agent loses access.
💡 Getting an OAuth token. How you obtain the initial access and refresh tokens depends on the MCP server — consult its documentation. Once you have them, store them in a vault credential using the shape above; Anthropic auto-refreshes via the
refresh.token_endpointfrom there.
Scoping: Vaults are workspace-scoped. Anyone with developer+ role in the API workspace can create, read (metadata only — secrets are write-only), and attach vaults. vault_ids can be set at session create time but not via session update (the SDK docstring says "Not yet supported; requests setting this field are rejected").
Skills
Skills are reusable, filesystem-based resources that provide your agent with domain-specific expertise: workflows, context, and best practices that transform general-purpose agents into specialists. Unlike prompts (conversation-level instructions for one-off tasks), skills load on-demand and eliminate the need to repeatedly provide the same guidance across multiple conversations.
Two types — both work the same way; the agent automatically uses them when relevant to the task at hand:
| Type | What it is |
|---|---|
| Pre-built Anthropic skills | Common document tasks (PowerPoint, Excel, Word, PDF). Reference by name (e.g. xlsx). |
| Custom skills | Skills you've created in your organization via the Skills API. Reference by skill_id + optional version. |
Max 64 skills per agent. Agent creation uses managed-agents-2026-04-01; the separate Skills API (for managing custom skill definitions) uses skills-2025-10-02.
Enabling skills on a session
Skills are attached to the agent definition via agents.create():
const agent = await client.beta.agents.create(
{
name: "Financial Agent",
model: "{{OPUS_ID}}",
system: "You are a financial analysis agent.",
skills: [
{ type: "anthropic", skill_id: "xlsx" },
{ type: "custom", skill_id: "skill_abc123", version: "latest" },
],
}
);
Python:
agent = client.beta.agents.create(
name="Financial Agent",
model="{{OPUS_ID}}",
system="You are a financial analysis agent.",
skills=[
{"type": "anthropic", "skill_id": "xlsx"},
{"type": "custom", "skill_id": "skill_abc123", "version": "latest"},
]
)
Skill reference fields:
| Field | Anthropic skill | Custom skill |
|---|---|---|
type |
"anthropic" |
"custom" |
skill_id |
Skill name (e.g. "xlsx", "docx", "pptx", "pdf") |
Skill ID from Skills API (e.g. "skill_abc123") |
version |
— | "latest" or a specific version number |
Skills API
| Operation | Method | Path |
|---|---|---|
| Create Skill | POST |
/v1/skills |
| List Skills | GET |
/v1/skills |
| Get Skill | GET |
/v1/skills/{id} |
| Delete Skill | DELETE |
/v1/skills/{id} |
| Create Version | POST |
/v1/skills/{id}/versions |
| List Versions | GET |
/v1/skills/{id}/versions |
| Get Version | GET |
/v1/skills/{id}/versions/{version} |
| Delete Version | DELETE |
/v1/skills/{id}/versions/{version} |