# Define all available tools
ALL_TOOLS = {
# Customer data
"get_customer": customer_tools.get_customer,
"get_order": customer_tools.get_order,
"get_payment_history": customer_tools.get_payment_history,
"get_support_history": customer_tools.get_support_history,
# Resolution actions
"process_refund": resolution_tools.process_refund,
"send_replacement": resolution_tools.send_replacement,
"update_subscription": resolution_tools.update_subscription,
# Technical tools
"check_service_status": technical_tools.check_service_status,
"reset_user_auth": technical_tools.reset_user_auth,
"clear_cache": technical_tools.clear_cache,
# Escalation
"create_ticket": escalation_tools.create_ticket,
"escalate_to_human": escalation_tools.escalate_to_human,
"get_agent_queue": escalation_tools.get_agent_queue,
# Communication
"send_email": comms_tools.send_email,
"send_sms": comms_tools.send_sms,
}
# Define scoped tool sets per role
TOOL_SCOPES = {
# Intake agent: identify issue, gather context, route
"intake_agent": [
"get_customer", "get_order", "get_support_history",
"create_ticket"
],
# Billing specialist: full customer data, billing actions only
"billing_specialist": [
"get_customer", "get_order", "get_payment_history",
"process_refund", "update_subscription",
"send_email"
],
# Technical specialist: diagnostic and fix tools, no billing
"technical_specialist": [
"get_customer", "get_order",
"check_service_status", "reset_user_auth", "clear_cache",
"send_email"
],
# Escalation coordinator: oversight tools, full escalation access
"escalation_coordinator": [
"get_customer", "get_order", "get_support_history",
"create_ticket", "escalate_to_human", "get_agent_queue",
"send_email", "send_sms"
],
}
def get_tools_for_role(role: str) -> list:
"""Return the tool definitions for a specific agent role."""
tool_names = TOOL_SCOPES.get(role, [])
return [ALL_TOOLS[name] for name in tool_names if name in ALL_TOOLS]
# Usage
intake_tools = get_tools_for_role("intake_agent") # 4 tools
billing_tools = get_tools_for_role("billing_specialist") # 6 tools
tech_tools = get_tools_for_role("technical_specialist") # 6 tools
MCP Server-Level Scoping
For MCP servers, scope can be enforced at the authentication layer:
# MCP server with role-based tool access
TOOL_PERMISSIONS = {
"read_only_key": ["get_customer", "get_order", "search_knowledge_base"],
"billing_key": ["get_customer", "get_order", "get_payment_history", "process_refund"],
"admin_key": ["get_customer", "get_order", "get_payment_history",
"process_refund", "delete_account", "export_data"],
}
@server.tool("process_refund")
async def process_refund(amount: float, order_id: str, api_key: str = Depends(auth)):
# Check that this API key has permission for this specific tool
allowed_tools = TOOL_PERMISSIONS.get(api_key, [])
if "process_refund" not in allowed_tools:
raise PermissionError("This API key does not have refund processing access")
return await refund_service.process(amount, order_id)
Key Takeaways
- Scope tools to roles — minimum necessary access for each agent function
- Benefits: reduced blast radius, better selection reliability, minimal footprint
- Implementation: pass different tool lists to different agent calls
- MCP scoping: authenticate clients to different tool subsets at the server level
- Never give all tools to all agents — explicit exam anti-pattern