- 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
188 lines
6.5 KiB
Python
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)
|