"""User, Role, and Permission management tools.""" import json from mcp.types import Tool from frappe_mcp.client.frappe_api import FrappeClient def tools() -> list[Tool]: return [ Tool( name="frappe_list_users", description="List Frappe users.", inputSchema={ "type": "object", "properties": { "enabled": {"type": "integer", "description": "1 for active, 0 for disabled"}, "limit": {"type": "integer", "default": 20}, }, }, ), Tool( name="frappe_get_user", description="Get a user's details and roles.", inputSchema={ "type": "object", "required": ["email"], "properties": { "email": {"type": "string"}, }, }, ), Tool( name="frappe_create_user", description="Create a new Frappe user.", inputSchema={ "type": "object", "required": ["email", "first_name"], "properties": { "email": {"type": "string"}, "first_name": {"type": "string"}, "last_name": {"type": "string"}, "send_welcome_email": {"type": "integer", "default": 0}, "roles": { "type": "array", "items": {"type": "string"}, "description": "List of role names e.g. ['System Manager', 'Sales User']", }, }, }, ), Tool( name="frappe_assign_role", description="Assign a role to an existing user.", inputSchema={ "type": "object", "required": ["email", "role"], "properties": { "email": {"type": "string"}, "role": {"type": "string"}, }, }, ), Tool( name="frappe_remove_role", description="Remove a role from a user.", inputSchema={ "type": "object", "required": ["email", "role"], "properties": { "email": {"type": "string"}, "role": {"type": "string"}, }, }, ), Tool( name="frappe_list_roles", description="List all available roles in the system.", inputSchema={"type": "object", "properties": {}}, ), Tool( name="frappe_set_doctype_permission", description="Set role permissions on a DocType.", inputSchema={ "type": "object", "required": ["doctype", "role"], "properties": { "doctype": {"type": "string"}, "role": {"type": "string"}, "read": {"type": "integer", "default": 1}, "write": {"type": "integer", "default": 0}, "create": {"type": "integer", "default": 0}, "delete": {"type": "integer", "default": 0}, "submit": {"type": "integer", "default": 0}, "cancel": {"type": "integer", "default": 0}, "amend": {"type": "integer", "default": 0}, "report": {"type": "integer", "default": 0}, "export": {"type": "integer", "default": 0}, "import": {"type": "integer", "default": 0}, "print": {"type": "integer", "default": 0}, "email": {"type": "integer", "default": 0}, }, }, ), ] def handlers() -> dict: return { "frappe_list_users": _list_users, "frappe_get_user": _get_user, "frappe_create_user": _create_user, "frappe_assign_role": _assign_role, "frappe_remove_role": _remove_role, "frappe_list_roles": _list_roles, "frappe_set_doctype_permission": _set_doctype_permission, } async def _list_users(args: dict) -> str: client = FrappeClient() filters = [] if "enabled" in args: filters.append(["enabled", "=", args["enabled"]]) result = await client.get_list( "User", fields=["name", "full_name", "email", "enabled", "last_login"], filters=filters if filters else None, limit=args.get("limit", 20), ) return json.dumps(result, indent=2) async def _get_user(args: dict) -> str: client = FrappeClient() result = await client.get_doc("User", args["email"]) return json.dumps(result, indent=2) async def _create_user(args: dict) -> str: client = FrappeClient() roles = [{"role": r} for r in args.get("roles", [])] payload = { "email": args["email"], "first_name": args["first_name"], "last_name": args.get("last_name", ""), "send_welcome_email": args.get("send_welcome_email", 0), "roles": roles, } result = await client.create_doc("User", payload) return json.dumps(result, indent=2) async def _assign_role(args: dict) -> str: client = FrappeClient() user = await client.get_doc("User", args["email"]) existing_roles = [r["role"] for r in user.get("roles", [])] if args["role"] not in existing_roles: user["roles"].append({"role": args["role"]}) result = await client.update_doc("User", args["email"], {"roles": user["roles"]}) return json.dumps(result, indent=2) return f"User {args['email']} already has role {args['role']}" async def _remove_role(args: dict) -> str: client = FrappeClient() user = await client.get_doc("User", args["email"]) updated_roles = [r for r in user.get("roles", []) if r["role"] != args["role"]] result = await client.update_doc("User", args["email"], {"roles": updated_roles}) return json.dumps(result, indent=2) async def _list_roles(args: dict) -> str: client = FrappeClient() result = await client.get_list("Role", fields=["name", "disabled"], limit=100) return json.dumps(result, indent=2) async def _set_doctype_permission(args: dict) -> str: client = FrappeClient() payload = {k: v for k, v in args.items()} result = await client.call_method( "frappe.client.set_value", doctype="DocPerm", name=None, fieldname=payload, ) return json.dumps(result, indent=2)