diff --git a/docs/_static/llama-stack-spec.html b/docs/_static/llama-stack-spec.html
index f9e4bb38e..67facdac6 100644
--- a/docs/_static/llama-stack-spec.html
+++ b/docs/_static/llama-stack-spec.html
@@ -5547,6 +5547,31 @@
"additionalProperties": {
"$ref": "#/components/schemas/ToolParamDefinition"
}
+ },
+ "annotations": {
+ "type": "object",
+ "additionalProperties": {
+ "oneOf": [
+ {
+ "type": "null"
+ },
+ {
+ "type": "boolean"
+ },
+ {
+ "type": "number"
+ },
+ {
+ "type": "string"
+ },
+ {
+ "type": "array"
+ },
+ {
+ "type": "object"
+ }
+ ]
+ }
}
},
"additionalProperties": false,
@@ -6447,6 +6472,31 @@
}
]
}
+ },
+ "annotations": {
+ "type": "object",
+ "additionalProperties": {
+ "oneOf": [
+ {
+ "type": "null"
+ },
+ {
+ "type": "boolean"
+ },
+ {
+ "type": "number"
+ },
+ {
+ "type": "string"
+ },
+ {
+ "type": "array"
+ },
+ {
+ "type": "object"
+ }
+ ]
+ }
}
},
"additionalProperties": false,
@@ -8461,6 +8511,31 @@
},
"description": {
"type": "string"
+ },
+ "annotations": {
+ "type": "object",
+ "additionalProperties": {
+ "oneOf": [
+ {
+ "type": "null"
+ },
+ {
+ "type": "boolean"
+ },
+ {
+ "type": "number"
+ },
+ {
+ "type": "string"
+ },
+ {
+ "type": "array"
+ },
+ {
+ "type": "object"
+ }
+ ]
+ }
}
},
"additionalProperties": false,
@@ -10962,6 +11037,31 @@
}
]
}
+ },
+ "annotations": {
+ "type": "object",
+ "additionalProperties": {
+ "oneOf": [
+ {
+ "type": "null"
+ },
+ {
+ "type": "boolean"
+ },
+ {
+ "type": "number"
+ },
+ {
+ "type": "string"
+ },
+ {
+ "type": "array"
+ },
+ {
+ "type": "object"
+ }
+ ]
+ }
}
},
"additionalProperties": false,
diff --git a/docs/_static/llama-stack-spec.yaml b/docs/_static/llama-stack-spec.yaml
index 9175c97fc..3570e2e34 100644
--- a/docs/_static/llama-stack-spec.yaml
+++ b/docs/_static/llama-stack-spec.yaml
@@ -3912,6 +3912,16 @@ components:
type: object
additionalProperties:
$ref: '#/components/schemas/ToolParamDefinition'
+ annotations:
+ type: object
+ additionalProperties:
+ oneOf:
+ - type: 'null'
+ - type: boolean
+ - type: number
+ - type: string
+ - type: array
+ - type: object
additionalProperties: false
required:
- tool_name
@@ -4610,6 +4620,16 @@ components:
- type: string
- type: array
- type: object
+ annotations:
+ type: object
+ additionalProperties:
+ oneOf:
+ - type: 'null'
+ - type: boolean
+ - type: number
+ - type: string
+ - type: array
+ - type: object
additionalProperties: false
required:
- name
@@ -5962,6 +5982,16 @@ components:
type: string
description:
type: string
+ annotations:
+ type: object
+ additionalProperties:
+ oneOf:
+ - type: 'null'
+ - type: boolean
+ - type: number
+ - type: string
+ - type: array
+ - type: object
additionalProperties: false
required:
- input_schema
@@ -7722,6 +7752,16 @@ components:
- type: string
- type: array
- type: object
+ annotations:
+ type: object
+ additionalProperties:
+ oneOf:
+ - type: 'null'
+ - type: boolean
+ - type: number
+ - type: string
+ - type: array
+ - type: object
additionalProperties: false
required:
- identifier
diff --git a/llama_stack/apis/agents/openai_responses.py b/llama_stack/apis/agents/openai_responses.py
index 27b85e2d6..b9e30e3ad 100644
--- a/llama_stack/apis/agents/openai_responses.py
+++ b/llama_stack/apis/agents/openai_responses.py
@@ -161,6 +161,7 @@ class MCPListToolsTool(BaseModel):
input_schema: dict[str, Any]
name: str
description: str | None = None
+ annotations: dict[str, Any] | None = None
@json_schema_type
diff --git a/llama_stack/apis/tools/tools.py b/llama_stack/apis/tools/tools.py
index 7d1eeeefb..f8f4ad1bc 100644
--- a/llama_stack/apis/tools/tools.py
+++ b/llama_stack/apis/tools/tools.py
@@ -27,6 +27,15 @@ class ToolParameter(BaseModel):
default: Any | None = None
+@json_schema_type
+class ToolAnnotations(BaseModel):
+ title: str | None = None
+ readOnlyHint: bool | None = None
+ destructiveHint: bool | None = None
+ idempotentHint: bool | None = None
+ openWorldHint: bool | None = None
+
+
@json_schema_type
class Tool(Resource):
type: Literal[ResourceType.tool] = ResourceType.tool
@@ -34,6 +43,7 @@ class Tool(Resource):
description: str
parameters: list[ToolParameter]
metadata: dict[str, Any] | None = None
+ annotations: ToolAnnotations | None = None
@json_schema_type
@@ -42,6 +52,7 @@ class ToolDef(BaseModel):
description: str | None = None
parameters: list[ToolParameter] | None = None
metadata: dict[str, Any] | None = None
+ annotations: ToolAnnotations | None = None
@json_schema_type
diff --git a/llama_stack/distribution/routing_tables/toolgroups.py b/llama_stack/distribution/routing_tables/toolgroups.py
index b86f057bd..453e5c2e7 100644
--- a/llama_stack/distribution/routing_tables/toolgroups.py
+++ b/llama_stack/distribution/routing_tables/toolgroups.py
@@ -74,6 +74,7 @@ class ToolGroupsRoutingTable(CommonRoutingTableImpl, ToolGroups):
parameters=t.parameters or [],
metadata=t.metadata,
provider_id=toolgroup.provider_id,
+ annotations=t.annotations,
)
)
diff --git a/llama_stack/models/llama/datatypes.py b/llama_stack/models/llama/datatypes.py
index 7f1ebed55..02fdf2604 100644
--- a/llama_stack/models/llama/datatypes.py
+++ b/llama_stack/models/llama/datatypes.py
@@ -11,6 +11,8 @@ from typing import Annotated, Any, Literal
from pydantic import BaseModel, ConfigDict, Field, field_serializer, field_validator
+from apis.tools import ToolAnnotations
+
# The goal is that these set of types are relevant for all Llama models.
# That isn't the current state yet -- e.g., BuiltinTool is somewhat specific to
# the llama3 series of models.
@@ -99,6 +101,7 @@ class ToolDefinition(BaseModel):
tool_name: BuiltinTool | str
description: str | None = None
parameters: dict[str, ToolParamDefinition] | None = None
+ annotations: ToolAnnotations | None = None
@field_validator("tool_name", mode="before")
@classmethod
diff --git a/llama_stack/providers/inline/agents/meta_reference/agent_instance.py b/llama_stack/providers/inline/agents/meta_reference/agent_instance.py
index 4d2b9f8bf..2eb10d7aa 100644
--- a/llama_stack/providers/inline/agents/meta_reference/agent_instance.py
+++ b/llama_stack/providers/inline/agents/meta_reference/agent_instance.py
@@ -843,6 +843,7 @@ class ChatAgent(ShieldRunnerMixin):
)
for param in tool_def.parameters
},
+ annotations=tool_def.annotations,
)
tool_name_to_args[tool_def.identifier] = toolgroup_to_args.get(toolgroup_name, {})
diff --git a/llama_stack/providers/inline/agents/meta_reference/openai_responses.py b/llama_stack/providers/inline/agents/meta_reference/openai_responses.py
index f291593f4..05c1ae6ba 100644
--- a/llama_stack/providers/inline/agents/meta_reference/openai_responses.py
+++ b/llama_stack/providers/inline/agents/meta_reference/openai_responses.py
@@ -666,6 +666,7 @@ class OpenAIResponsesImpl:
},
"required": [p.name for p in t.parameters if p.required],
},
+ annotations=t.annotations,
)
)
else:
diff --git a/llama_stack/providers/utils/tools/mcp.py b/llama_stack/providers/utils/tools/mcp.py
index fbf992c82..e1591daac 100644
--- a/llama_stack/providers/utils/tools/mcp.py
+++ b/llama_stack/providers/utils/tools/mcp.py
@@ -57,6 +57,7 @@ async def list_mcp_tools(endpoint: str, headers: dict[str, str]) -> ListToolDefs
description=param_schema.get("description", ""),
)
)
+ annotations = getattr(tool, "annotations", None)
tools.append(
ToolDef(
name=tool.name,
@@ -65,6 +66,7 @@ async def list_mcp_tools(endpoint: str, headers: dict[str, str]) -> ListToolDefs
metadata={
"endpoint": endpoint,
},
+ annotations=annotations,
)
)
return ListToolDefsResponse(data=tools)