MOHAN 2ee93048e1 feat: Add tools for managing server scripts, client scripts, translations, assignment rules, user permissions, webhooks, API keys, and workflows
- Implemented server and client script management tools in `frappe_mcp/tools/scripts.py`
- Added translation and user permission management tools in `frappe_mcp/tools/translations.py`
- Created user and role management tools in `frappe_mcp/tools/users.py`
- Developed webhook and API key management tools in `frappe_mcp/tools/webhooks.py`
- Introduced workflow management tools in `frappe_mcp/tools/workflow_tools.py`
- Added `pyproject.toml` for project metadata and dependencies
2026-04-21 20:26:45 +05:30

188 lines
6.5 KiB
Python

"""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)