Agent Tool Design
Principles
- One tool, one responsibility — don't combine unrelated actions
- Descriptive names —
send_telegram_message not send_msg
- Rich descriptions — the LLM decides which tool to use based on the description
- Always return useful errors — never throw silently
- Idempotent where possible — safe to retry on failure
MCP Tool Schema (Zod)
server.registerTool('create_task', {
title: 'Create Task',
description: `Create a new task in Julia's backend.
Use when the user asks to add, remember, or track something.
Returns the created task with its ID.
Example: create_task({ title: "Buy groceries" })`,
inputSchema: z.object({
title: z.string().min(1).max(500).describe('Task title — be specific and actionable'),
priority: z.enum(['low', 'medium', 'high']).default('medium').optional(),
}),
annotations: {
readOnlyHint: false,
destructiveHint: false,
idempotentHint: false,
}
}, async ({ title, priority }) => {
try {
const task = await backend.createTask({ title, priority });
return { content: [{ type: 'text', text: JSON.stringify(task) }] };
} catch (err) {
return { content: [{ type: 'text', text: `Error: ${err.message}` }] };
}
});
Tool Description Template
[One sentence: what it does]
Use when [trigger condition].
[Args description if non-obvious]
Returns [what the agent gets back].
Example: tool_name({ param: "value" })
Error Return Convention
// Always return errors as text content — never throw from a tool
// The LLM can read the error and decide what to do
return { content: [{ type: 'text', text: `Error: ${message}` }] };
Julia's Tool Categories
| Category |
Examples |
| Communication |
send_telegram_message, get_pending_messages |
| Task management |
create_task, update_task, list_tasks |
| System |
get_pm2_status, restart_service, check_health |
| Delegation |
claude_task, claude_code_review (cowork-mcp) |
1---2name: agent-tool-design3description: Design reliable, well-documented tools for LLM agents — input schemas, error returns, idempotency, and naming conventions. Use when adding new MCP tools to bridge, cowork-mcp, or the orchestrator.4---56# Agent Tool Design78## Principles9101. **One tool, one responsibility** — don't combine unrelated actions112. **Descriptive names** — `send_telegram_message` not `send_msg`123. **Rich descriptions** — the LLM decides which tool to use based on the description134. **Always return useful errors** — never throw silently145. **Idempotent where possible** — safe to retry on failure1516## MCP Tool Schema (Zod)17```ts18server.registerTool('create_task', {19 title: 'Create Task',20 description: `Create a new task in Julia's backend.21 Use when the user asks to add, remember, or track something.22 Returns the created task with its ID.23 Example: create_task({ title: "Buy groceries" })`,24 inputSchema: z.object({25 title: z.string().min(1).max(500).describe('Task title — be specific and actionable'),26 priority: z.enum(['low', 'medium', 'high']).default('medium').optional(),27 }),28 annotations: {29 readOnlyHint: false,30 destructiveHint: false,31 idempotentHint: false,32 }33}, async ({ title, priority }) => {34 try {35 const task = await backend.createTask({ title, priority });36 return { content: [{ type: 'text', text: JSON.stringify(task) }] };37 } catch (err) {38 return { content: [{ type: 'text', text: `Error: ${err.message}` }] };39 }40});41```4243## Tool Description Template44```45[One sentence: what it does]46Use when [trigger condition].47[Args description if non-obvious]48Returns [what the agent gets back].49Example: tool_name({ param: "value" })50```5152## Error Return Convention53```ts54// Always return errors as text content — never throw from a tool55// The LLM can read the error and decide what to do56return { content: [{ type: 'text', text: `Error: ${message}` }] };57```5859## Julia's Tool Categories60| Category | Examples |61|----------|---------|62| Communication | `send_telegram_message`, `get_pending_messages` |63| Task management | `create_task`, `update_task`, `list_tasks` |64| System | `get_pm2_status`, `restart_service`, `check_health` |65| Delegation | `claude_task`, `claude_code_review` (cowork-mcp) |