You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The SDK's tool system has zero security classification. Every registered tool — whether it reads a file or deletes a database — is treated identically by the event loop. There is no way to declare a tool's safety profile, and no built-in permission gate before tool execution.
Updated based on feedback in the comments — generalized to a metadata dict so this interface also covers #1261 (tags) and #1598 (tool-type detection), and added MCP annotation mapping. Original proposal used security-specific fields only.
Rather than adding security-specific fields, introduce a generic metadata dict on AgentTool with thin typed accessors for well-known keys. This handles this issue, #1261 (tags), and #1598 (tool-type detection) with one interface.
MCP tools:MCPAgentTool maps the MCP spec's tool annotations (readOnlyHint, destructiveHint, idempotentHint, openWorldHint) into the same metadata dict, so hooks reason about MCP and native tools uniformly. Servers that don't provide annotations yield empty metadata — "unclassified," not silently "safe."
Classification model: Instead of two independent booleans (which leave (False, False) ambiguous), the initial well-known keys express the three-tier model cleanly: no flags = unclassified, read_only=True = no side effects, destructive=True = irreversible. requires_confirmation is an orthogonal gating hint.
Users opt in by adding hooks=[PermissionPolicy()] to their Agent.
Explicitly out of scope for this issue
Capability intersection across agent delegation — trust propagation in multi-agent graphs is a separate design.
Budget / cost enforcement — orthogonal to safety classification; belongs in a cost-control proposal.
Runtime policy hot-reload — deployment concern, not SDK surface.
Trade-offs
Concern
Analysis
MCP tools can't use @tool decorator
MCPAgentTool maps MCP spec tool annotations (readOnlyHint, destructiveHint, idempotentHint, openWorldHint) into the shared metadata dict. No name heuristics needed.
Defaults matter
Typed accessors return False when the key is absent, but absence means "unclassified," not "safe." Policies should gate on explicit read_only=True, not on the absence of destructive=True.
Doesn't this duplicate hooks?
Hooks enable custom logic, but without metadata on the tool, every hook must hardcode tool-name-to-permission mappings. Metadata makes policies declarative and portable across projects.
Why a generic metadata dict instead of typed fields?
Keeps the interface extensible — #1261 (tags) and #1598 (tool-type detection) want different keys on the same surface. Typed accessors give IDE autocomplete and type-safety for the well-known keys without locking the schema.
Breaking change risk
Zero. All new fields are optional with backward-compatible defaults. Existing @tool functions and AgentTool subclasses work unchanged.
References
@tool decorator: src/strands/tools/decorator.py
ToolSpec: src/strands/types/tools.py
AgentTool: src/strands/tools/tools.py
BeforeToolCallEvent: src/strands/hooks/events.py
Hook dispatch in executor: src/strands/tools/executors/_executor.py
Problem Statement
The SDK's tool system has zero security classification. Every registered tool — whether it reads a file or deletes a database — is treated identically by the event loop. There is no way to declare a tool's safety profile, and no built-in permission gate before tool execution.
What exists today:
@tooldecorator supports only:func,description,inputSchema,name,context. No security parameters.ToolSpecTypedDict has only:description,inputSchema,name,outputSchema. No permission fields.AgentToolbase class has:tool_name,tool_spec,tool_type,supports_hot_reload,is_dynamic. No security properties.BeforeToolCallEventwithcancel_toolfield enables permission gating via hooks, but requires users to implement all classification logic externally.MCPClient.ToolFiltersfilters tools at load time by name pattern, but no runtime permission checks.What's missing:
Why this matters:
BeforeToolCallEvent+cancel_tool). What's missing is the metadata on tools for hooks to reason about, and a reference implementation that users can adopt.Related Issues
AgentToolproperties for hook-based policies (type metadata)Proposed Solution
Phase 1: Generic tool metadata + typed accessors for safety (non-breaking)
Rather than adding security-specific fields, introduce a generic
metadatadict onAgentToolwith thin typed accessors for well-known keys. This handles this issue, #1261 (tags), and #1598 (tool-type detection) with one interface.AgentToolbase class:@tooldecorator — accepts either named safety params or a raw metadata dict (they populate the same underlying map):MCP tools:
MCPAgentToolmaps the MCP spec's tool annotations (readOnlyHint,destructiveHint,idempotentHint,openWorldHint) into the samemetadatadict, so hooks reason about MCP and native tools uniformly. Servers that don't provide annotations yield empty metadata — "unclassified," not silently "safe."Classification model: Instead of two independent booleans (which leave
(False, False)ambiguous), the initial well-known keys express the three-tier model cleanly: no flags = unclassified,read_only=True= no side effects,destructive=True= irreversible.requires_confirmationis an orthogonal gating hint.Phase 2: Reference
PermissionPolicyhook (optional, opt-in)Provide a reference
PermissionPolicyhook that uses the typed accessors:Users opt in by adding
hooks=[PermissionPolicy()]to their Agent.Explicitly out of scope for this issue
Trade-offs
@tooldecoratorMCPAgentToolmaps MCP spec tool annotations (readOnlyHint,destructiveHint,idempotentHint,openWorldHint) into the sharedmetadatadict. No name heuristics needed.Falsewhen the key is absent, but absence means "unclassified," not "safe." Policies should gate on explicitread_only=True, not on the absence ofdestructive=True.metadatadict instead of typed fields?@toolfunctions andAgentToolsubclasses work unchanged.References
@tooldecorator:src/strands/tools/decorator.pyToolSpec:src/strands/types/tools.pyAgentTool:src/strands/tools/tools.pyBeforeToolCallEvent:src/strands/hooks/events.pysrc/strands/tools/executors/_executor.py