feat: add signature tools for digital signature integration

Adds 4 Python tool registrations that call EspoCRM's SmartAssistant
executeTool endpoint with the DigitalSignature plugin tools:

- send_for_signature — send document for signing with auto-resolved signers
- check_signature_status — query status of signature requests
- remind_signers — send WhatsApp reminders to pending signers
- list_pending_signatures — show all awaiting signature requests

Tools are registered under the "signature" toolset, enabled by default.
Requires DigitalSignature extension v2.0.0+ on the EspoCRM side.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-20 11:06:21 +00:00
parent 51c76c1cf9
commit 84269a8d51
2 changed files with 178 additions and 0 deletions
+175
View File
@@ -0,0 +1,175 @@
"""Signature tools: send_for_signature, check_signature_status, remind_signers, list_pending_signatures."""
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from mcp_server.espocrm_client import EspoCrmClient
from mcp_server.tools._helpers import ok, fail
def register_signature_tools(
tools: dict,
crm: "EspoCrmClient",
case_id: str | None,
user_id: str | None,
context: dict,
):
"""Register digital signature tools."""
async def send_for_signature(
documentId: str | None = None,
documentName: str | None = None,
signerContactIds: list[str] | None = None,
signingMode: str = "Parallel",
message: str | None = None,
notifyViaWhatsApp: bool = True,
) -> str:
"""Send a document for digital signature. Resolves signers from case contacts automatically."""
if not documentId and not documentName:
return fail("יש לציין שם מסמך או מזהה מסמך")
params = {
"signingMode": signingMode,
"notifyViaWhatsApp": notifyViaWhatsApp,
}
if documentId:
params["documentId"] = documentId
if documentName:
params["documentName"] = documentName
if signerContactIds:
params["signerContactIds"] = signerContactIds
if message:
params["message"] = message
try:
result = await crm.post("SmartAssistant/action/executeTool", {
"tool": "send_for_signature",
"params": params,
"caseId": case_id,
"userId": user_id,
})
if result.get("success"):
return ok(result.get("message", "המסמך נשלח לחתימה"))
return fail(result.get("message", "שגיאה בשליחה לחתימה"))
except Exception as e:
return fail(f"שגיאה בשליחה לחתימה: {e}")
async def check_signature_status(
signatureRequestId: str | None = None,
documentName: str | None = None,
) -> str:
"""Check the status of a signature request. Can look up by ID or by document name."""
params = {}
if signatureRequestId:
params["signatureRequestId"] = signatureRequestId
if documentName:
params["documentName"] = documentName
try:
result = await crm.post("SmartAssistant/action/executeTool", {
"tool": "check_signature_status",
"params": params,
"caseId": case_id,
"userId": user_id,
})
if result.get("success"):
return ok(result.get("message", "אין מידע"))
return fail(result.get("message", "שגיאה בבדיקת סטטוס"))
except Exception as e:
return fail(f"שגיאה בבדיקת סטטוס חתימה: {e}")
async def remind_signers(signatureRequestId: str) -> str:
"""Send reminder to pending signers on a signature request via WhatsApp and email."""
try:
result = await crm.post("SmartAssistant/action/executeTool", {
"tool": "remind_signers",
"params": {"signatureRequestId": signatureRequestId},
"caseId": case_id,
"userId": user_id,
})
if result.get("success"):
return ok(result.get("message", "תזכורות נשלחו"))
return fail(result.get("message", "שגיאה בשליחת תזכורות"))
except Exception as e:
return fail(f"שגיאה בשליחת תזכורות: {e}")
async def list_pending_signatures(status: str | None = None) -> str:
"""List all pending signature requests. Optionally filter by status."""
params = {}
if status:
params["status"] = status
try:
result = await crm.post("SmartAssistant/action/executeTool", {
"tool": "list_pending_signatures",
"params": params,
"caseId": case_id,
"userId": user_id,
})
if result.get("success"):
return ok(result.get("message", "אין חתימות ממתינות"))
return fail(result.get("message", "שגיאה בשליפת חתימות"))
except Exception as e:
return fail(f"שגיאה בשליפת חתימות ממתינות: {e}")
# Register all tools
tools["send_for_signature"] = {
"fn": send_for_signature,
"description": "שלח מסמך לחתימה דיגיטלית. מזהה חותמים אוטומטית מאנשי הקשר בתיק. שולח הודעת WhatsApp עם קישור לחתימה.",
"parameters": {
"type": "object",
"properties": {
"documentId": {"type": "string", "description": "מזהה מסמך (Document ID)"},
"documentName": {"type": "string", "description": "שם המסמך (חיפוש חלקי)"},
"signerContactIds": {"type": "array", "items": {"type": "string"}, "description": "רשימת מזהי אנשי קשר ספציפיים לחתימה (אופציונלי — ברירת מחדל: כל אנשי הקשר בתיק)"},
"signingMode": {"type": "string", "enum": ["Parallel", "Sequential"], "description": "מצב חתימה (ברירת מחדל: Parallel)"},
"message": {"type": "string", "description": "הודעה אישית לחותמים"},
"notifyViaWhatsApp": {"type": "boolean", "description": "שלח הודעת WhatsApp (ברירת מחדל: true)"},
},
"required": [],
},
"agentic": False,
}
tools["check_signature_status"] = {
"fn": check_signature_status,
"description": "בדוק סטטוס חתימה. חיפוש לפי מזהה בקשה או שם מסמך. מציג מי חתם ומי ממתין.",
"parameters": {
"type": "object",
"properties": {
"signatureRequestId": {"type": "string", "description": "מזהה בקשת חתימה"},
"documentName": {"type": "string", "description": "שם מסמך לחיפוש"},
},
"required": [],
},
"agentic": False,
}
tools["remind_signers"] = {
"fn": remind_signers,
"description": "שלח תזכורת לחותמים ממתינים בבקשת חתימה — WhatsApp ומייל.",
"parameters": {
"type": "object",
"properties": {
"signatureRequestId": {"type": "string", "description": "מזהה בקשת חתימה"},
},
"required": ["signatureRequestId"],
},
"agentic": False,
}
tools["list_pending_signatures"] = {
"fn": list_pending_signatures,
"description": "הצג רשימת בקשות חתימה ממתינות. מציג שם מסמך, חותמים וסטטוס לכל בקשה.",
"parameters": {
"type": "object",
"properties": {
"status": {"type": "string", "enum": ["Pending", "PartiallySigned", "FieldPlacement"], "description": "סינון לפי סטטוס (אופציונלי)"},
},
"required": [],
},
"agentic": False,
}