Tool AnnotationsΒΆ
Tool annotations provide metadata hints about tool behavior, helping clients and UIs make informed decisions about how to present and use tools. ContextForge supports the standard MCP annotation types for enhanced tool interaction.
OverviewΒΆ
Tool annotations are optional metadata that can be attached to tools to provide behavioral hints such as:
- Safety indicators: Whether a tool is read-only or potentially destructive
- Execution hints: Whether a tool is idempotent or operates in an open-world assumption
- UI hints: How tools should be presented in user interfaces
Supported Annotation TypesΒΆ
| Annotation | Type | Description |
|---|---|---|
readOnlyHint | boolean | Indicates the tool only reads data and doesn't modify state |
destructiveHint | boolean | Warns that the tool may cause irreversible changes |
idempotentHint | boolean | Indicates the tool can be called multiple times safely |
openWorldHint | boolean | Suggests the tool operates under open-world assumptions |
Setting Annotations via Admin UIΒΆ
Use the Admin UI to set tool annotations through the web interface:
- Navigate to Tools section in the Admin UI
- Click Edit on the desired tool
- In the Annotations field, enter JSON:
- Click Save to persist the annotations
Setting Annotations via APIΒΆ
Complete Annotation ExampleΒΆ
Here's a comprehensive example showing all available annotation types:
curl -X POST /tools \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{
"name": "file-reader",
"url": "http://example.com/api/read-file",
"description": "Safely reads file contents",
"annotations": {
"readOnlyHint": true,
"destructiveHint": false,
"idempotentHint": true,
"openWorldHint": false
}
}'
Individual Annotation ExamplesΒΆ
Read-Only ToolΒΆ
{
"name": "get-user-info",
"url": "http://api.example.com/users",
"annotations": {
"readOnlyHint": true
}
}
Destructive ToolΒΆ
{
"name": "delete-file",
"url": "http://api.example.com/files/delete",
"annotations": {
"destructiveHint": true,
"idempotentHint": false
}
}
Idempotent ToolΒΆ
{
"name": "create-user",
"url": "http://api.example.com/users",
"annotations": {
"idempotentHint": true,
"readOnlyHint": false
}
}
Updating Existing Tool AnnotationsΒΆ
curl -X PUT /tools/{tool_id} \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{
"annotations": {
"readOnlyHint": true,
"destructiveHint": false
}
}'
Gateway-Discovered ToolsΒΆ
When registering MCP servers via /gateways, tools are automatically discovered. To add annotations:
Gateway URL
- Direct installs (
uvx, pip, ordocker run):http://localhost:4444 - Docker Compose (nginx proxy):
http://localhost:8080
Set a base URL for the gateway API:
export BASE_URL="http://localhost:4444"
# export BASE_URL="http://localhost:8080" # docker-compose with nginx
Step 1: Register the GatewayΒΆ
curl -X POST $BASE_URL/gateways \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{
"name": "my-mcp-server",
"url": "http://localhost:8080/sse"
}'
Step 2: Add Annotations to Discovered ToolsΒΆ
# First, get the tool ID from the tools list
curl -H "Authorization: Bearer $TOKEN" $BASE_URL/tools
# Then update the specific tool with annotations
curl -X PUT $BASE_URL/tools/{discovered_tool_id} \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{
"annotations": {
"readOnlyHint": true,
"destructiveHint": false,
"idempotentHint": true
}
}'
Complex Annotation ScenariosΒΆ
Mixed Safety ToolΒΆ
A tool that reads configuration but may modify cache:
{
"annotations": {
"readOnlyHint": false,
"destructiveHint": false,
"idempotentHint": true,
"openWorldHint": true
}
}
High-Risk Administrative ToolΒΆ
A tool that performs system-level operations:
{
"annotations": {
"readOnlyHint": false,
"destructiveHint": true,
"idempotentHint": false,
"openWorldHint": false
}
}
Information Gathering ToolΒΆ
A tool that queries external APIs safely:
{
"annotations": {
"readOnlyHint": true,
"destructiveHint": false,
"idempotentHint": true,
"openWorldHint": true
}
}
Best PracticesΒΆ
1. Be Conservative with Safety HintsΒΆ
- Default to
destructiveHint: trueif uncertain - Only set
readOnlyHint: truefor genuinely safe operations
2. Consider Idempotency CarefullyΒΆ
- Set
idempotentHint: trueonly if multiple calls are truly safe - Database writes are typically not idempotent unless using upsert patterns
3. Use Open-World Hints AppropriatelyΒΆ
- Set
openWorldHint: truefor tools that query external data sources - Set
openWorldHint: falsefor tools operating on known, closed datasets
4. Combine Annotations LogicallyΒΆ
// β
Good: Read-only tool that's safe to retry
{
"readOnlyHint": true,
"destructiveHint": false,
"idempotentHint": true
}
// β Avoid: Contradictory annotations
{
"readOnlyHint": true,
"destructiveHint": true // Contradicts read-only
}
Viewing AnnotationsΒΆ
Annotations appear in tool JSON responses:
Response:
{
"id": "tool_123",
"name": "file-reader",
"url": "http://example.com/api/read-file",
"annotations": {
"readOnlyHint": true,
"destructiveHint": false,
"idempotentHint": true,
"openWorldHint": false
},
"description": "Safely reads file contents",
...
}
Integration with ClientsΒΆ
Many MCP clients use annotations to:
- Show warning dialogs for destructive tools
- Enable auto-retry for idempotent tools
- Cache results from read-only tools
- Adjust UI presentation based on safety hints
Properly annotated tools provide better user experiences and safer AI agent interactions.